Repository: forkgram/tdesktop Branch: dev Commit: be34977021b5 Files: 2804 Total size: 26.6 MB Directory structure: gitextract_khvlzyi6/ ├── .agents/ │ └── skills/ │ └── task-think/ │ ├── PROMPTS.md │ └── SKILL.md ├── .claude/ │ ├── commands/ │ │ ├── icon.md │ │ ├── planner.md │ │ ├── reflect.md │ │ ├── release.md │ │ ├── task.md │ │ └── withtest.md │ ├── grab_clipboard.ps1 │ ├── grab_clipboard.sh │ └── iterate.ps1 ├── .cursorignore ├── .devcontainer.json ├── .gitattributes ├── .github/ │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE/ │ │ ├── BUG_REPORT.yml │ │ ├── FEATURE_REQUEST.yml │ │ └── config.yml │ ├── dependabot.yml │ ├── scripts/ │ │ └── generate_changelog.py │ └── workflows/ │ ├── changelog.yml │ ├── docker.yml │ ├── full_source.yml │ ├── inno.yml │ ├── jekyll-gh-pages.yml │ ├── linux.yml │ ├── mac.yml │ ├── mac_packaged.yml │ ├── needs-user-action.yml │ ├── snap.yml │ ├── waiting-for-answer.yml │ └── win.yml ├── .gitignore ├── .gitmodules ├── AGENTS.md ├── CLAUDE.md ├── CMakeLists.txt ├── LEGAL ├── LICENSE ├── README.md ├── REVIEW.md ├── Telegram/ │ ├── CMakeLists.txt │ ├── Resources/ │ │ ├── animations/ │ │ │ ├── ban.tgs │ │ │ ├── blocked_peers_empty.tgs │ │ │ ├── cake.tgs │ │ │ ├── camera_outline.tgs │ │ │ ├── change_number.tgs │ │ │ ├── chat/ │ │ │ │ ├── sparkles_emoji.tgs │ │ │ │ ├── video_to_voice.tgs │ │ │ │ ├── voice_to_video.tgs │ │ │ │ └── white_flag_emoji.tgs │ │ │ ├── chat_link.tgs │ │ │ ├── cloud_filters.tgs │ │ │ ├── cloud_password/ │ │ │ │ ├── email.tgs │ │ │ │ ├── hint.tgs │ │ │ │ ├── intro.tgs │ │ │ │ ├── password_input.tgs │ │ │ │ └── validate.tgs │ │ │ ├── cocoon.tgs │ │ │ ├── collectible_phone.tgs │ │ │ ├── collectible_username.tgs │ │ │ ├── craft_failed.tgs │ │ │ ├── craft_progress.tgs │ │ │ ├── diamond.tgs │ │ │ ├── dice/ │ │ │ │ ├── bball_idle.tgs │ │ │ │ ├── dart_idle.tgs │ │ │ │ ├── dice_6.tgs │ │ │ │ ├── dice_idle.tgs │ │ │ │ ├── fball_idle.tgs │ │ │ │ ├── slot_0_idle.tgs │ │ │ │ ├── slot_1_idle.tgs │ │ │ │ ├── slot_2_idle.tgs │ │ │ │ ├── slot_back.tgs │ │ │ │ ├── slot_pull.tgs │ │ │ │ └── winners.tgs │ │ │ ├── discussion.tgs │ │ │ ├── edit_peers/ │ │ │ │ ├── direct_messages.tgs │ │ │ │ ├── topics.tgs │ │ │ │ ├── topics_list.tgs │ │ │ │ └── topics_tabs.tgs │ │ │ ├── filters.tgs │ │ │ ├── greeting.tgs │ │ │ ├── hello_status.tgs │ │ │ ├── hours.tgs │ │ │ ├── local_passcode_enter.tgs │ │ │ ├── location.tgs │ │ │ ├── media_forbidden.tgs │ │ │ ├── my_gifts_empty.tgs │ │ │ ├── no_chats.tgs │ │ │ ├── noresults.tgs │ │ │ ├── palette.tgs │ │ │ ├── passkeys.tgs │ │ │ ├── phone.tgs │ │ │ ├── photo_editor/ │ │ │ │ ├── arrow.tgs │ │ │ │ ├── blur.tgs │ │ │ │ ├── eraser.tgs │ │ │ │ ├── marker.tgs │ │ │ │ └── pen.tgs │ │ │ ├── photo_suggest_icon.tgs │ │ │ ├── profile/ │ │ │ │ ├── profile_muting.tgs │ │ │ │ └── profile_unmuting.tgs │ │ │ ├── robot.tgs │ │ │ ├── rtmp.tgs │ │ │ ├── search.tgs │ │ │ ├── show_or_premium_lastseen.tgs │ │ │ ├── show_or_premium_readtime.tgs │ │ │ ├── sleep.tgs │ │ │ ├── star_reaction/ │ │ │ │ ├── appear.tgs │ │ │ │ ├── center.tgs │ │ │ │ ├── effect1.tgs │ │ │ │ ├── effect2.tgs │ │ │ │ ├── effect3.tgs │ │ │ │ ├── select.tgs │ │ │ │ └── toast.tgs │ │ │ ├── starref_link.tgs │ │ │ ├── stats.tgs │ │ │ ├── stats_boosts.tgs │ │ │ ├── stats_earn.tgs │ │ │ ├── stop.tgs │ │ │ ├── swipe_action/ │ │ │ │ ├── archive.tgs │ │ │ │ ├── delete.tgs │ │ │ │ ├── disabled.tgs │ │ │ │ ├── mute.tgs │ │ │ │ ├── pin.tgs │ │ │ │ ├── read.tgs │ │ │ │ ├── unarchive.tgs │ │ │ │ ├── unmute.tgs │ │ │ │ ├── unpin.tgs │ │ │ │ └── unread.tgs │ │ │ ├── toast/ │ │ │ │ ├── chats_filter_in.tgs │ │ │ │ ├── saved_messages.tgs │ │ │ │ └── tagged.tgs │ │ │ ├── transcribe_loading.tgs │ │ │ ├── ttl.tgs │ │ │ ├── voice_ttl_idle.tgs │ │ │ ├── voice_ttl_start.tgs │ │ │ └── writing.tgs │ │ ├── art/ │ │ │ ├── background.tgv │ │ │ └── mac_setup.tiff │ │ ├── day-blue.tdesktop-theme │ │ ├── day-custom-base.tdesktop-theme │ │ ├── default_shortcuts-custom.json │ │ ├── export_html/ │ │ │ ├── css/ │ │ │ │ └── style.css │ │ │ └── js/ │ │ │ └── script.js │ │ ├── icons/ │ │ │ ├── calls/ │ │ │ │ ├── hands.lottie │ │ │ │ └── voice.lottie │ │ │ ├── poll/ │ │ │ │ ├── toast_hide_results.tgs │ │ │ │ └── uploading.tgs │ │ │ └── settings/ │ │ │ └── devices/ │ │ │ ├── device_desktop_mac.lottie │ │ │ ├── device_desktop_win.lottie │ │ │ ├── device_linux.lottie │ │ │ ├── device_linux_ubuntu.lottie │ │ │ ├── device_phone_android.lottie │ │ │ ├── device_phone_ios.lottie │ │ │ ├── device_tablet_ios.lottie │ │ │ ├── device_web_chrome.lottie │ │ │ ├── device_web_edge.lottie │ │ │ ├── device_web_firefox.lottie │ │ │ └── device_web_safari.lottie │ │ ├── iv_html/ │ │ │ ├── highlight.9.12.0.css │ │ │ ├── highlight.9.12.0.js │ │ │ ├── morphdom-umd.min.2.7.2.js │ │ │ ├── page.css │ │ │ └── page.js │ │ ├── langs/ │ │ │ ├── cloud_lang.strings │ │ │ ├── de.lproj/ │ │ │ │ └── Localizable.strings │ │ │ ├── en.lproj/ │ │ │ │ └── Localizable.strings │ │ │ ├── es.lproj/ │ │ │ │ └── Localizable.strings │ │ │ ├── it.lproj/ │ │ │ │ └── Localizable.strings │ │ │ ├── ko.lproj/ │ │ │ │ └── Localizable.strings │ │ │ ├── lang.strings │ │ │ ├── nl.lproj/ │ │ │ │ └── Localizable.strings │ │ │ ├── pt-BR.lproj/ │ │ │ │ └── Localizable.strings │ │ │ ├── refresh.py │ │ │ ├── refresh.sh │ │ │ └── stale.py │ │ ├── night-custom-base.tdesktop-theme │ │ ├── night-green.tdesktop-theme │ │ ├── night.tdesktop-theme │ │ ├── numbers.txt │ │ ├── picker_html/ │ │ │ ├── picker.css │ │ │ └── picker.js │ │ ├── qrc/ │ │ │ ├── emoji_1.qrc │ │ │ ├── emoji_2.qrc │ │ │ ├── emoji_3.qrc │ │ │ ├── emoji_4.qrc │ │ │ ├── emoji_5.qrc │ │ │ ├── emoji_6.qrc │ │ │ ├── emoji_7.qrc │ │ │ ├── emoji_8.qrc │ │ │ ├── emoji_preview.qrc │ │ │ ├── telegram/ │ │ │ │ ├── animations.qrc │ │ │ │ ├── export.qrc │ │ │ │ ├── iv.qrc │ │ │ │ ├── mac_icons.qrc │ │ │ │ ├── picker.qrc │ │ │ │ ├── sounds.qrc │ │ │ │ └── telegram.qrc │ │ │ └── telegram.qrc │ │ ├── uwp/ │ │ │ ├── AppX/ │ │ │ │ └── AppxManifest.xml │ │ │ └── priconfig.xml │ │ └── winrc/ │ │ ├── Telegram.manifest │ │ ├── Telegram.rc │ │ └── Updater.rc │ ├── SourceFiles/ │ │ ├── _other/ │ │ │ ├── packer.cpp │ │ │ ├── packer.h │ │ │ ├── startup_task_win.cpp │ │ │ ├── updater.h │ │ │ ├── updater_linux.cpp │ │ │ ├── updater_osx.m │ │ │ └── updater_win.cpp │ │ ├── api/ │ │ │ ├── api_as_copy.cpp │ │ │ ├── api_as_copy.h │ │ │ ├── api_attached_stickers.cpp │ │ │ ├── api_attached_stickers.h │ │ │ ├── api_authorizations.cpp │ │ │ ├── api_authorizations.h │ │ │ ├── api_blocked_peers.cpp │ │ │ ├── api_blocked_peers.h │ │ │ ├── api_bot.cpp │ │ │ ├── api_bot.h │ │ │ ├── api_chat_filters.cpp │ │ │ ├── api_chat_filters.h │ │ │ ├── api_chat_filters_remove_manager.cpp │ │ │ ├── api_chat_filters_remove_manager.h │ │ │ ├── api_chat_invite.cpp │ │ │ ├── api_chat_invite.h │ │ │ ├── api_chat_links.cpp │ │ │ ├── api_chat_links.h │ │ │ ├── api_chat_participants.cpp │ │ │ ├── api_chat_participants.h │ │ │ ├── api_cloud_password.cpp │ │ │ ├── api_cloud_password.h │ │ │ ├── api_common.cpp │ │ │ ├── api_common.h │ │ │ ├── api_compose_with_ai.cpp │ │ │ ├── api_compose_with_ai.h │ │ │ ├── api_confirm_phone.cpp │ │ │ ├── api_confirm_phone.h │ │ │ ├── api_credits.cpp │ │ │ ├── api_credits.h │ │ │ ├── api_credits_history_entry.cpp │ │ │ ├── api_credits_history_entry.h │ │ │ ├── api_earn.cpp │ │ │ ├── api_earn.h │ │ │ ├── api_editing.cpp │ │ │ ├── api_editing.h │ │ │ ├── api_filter_updates.h │ │ │ ├── api_global_privacy.cpp │ │ │ ├── api_global_privacy.h │ │ │ ├── api_hash.cpp │ │ │ ├── api_hash.h │ │ │ ├── api_invite_links.cpp │ │ │ ├── api_invite_links.h │ │ │ ├── api_media.cpp │ │ │ ├── api_media.h │ │ │ ├── api_messages_search.cpp │ │ │ ├── api_messages_search.h │ │ │ ├── api_messages_search_merged.cpp │ │ │ ├── api_messages_search_merged.h │ │ │ ├── api_peer_colors.cpp │ │ │ ├── api_peer_colors.h │ │ │ ├── api_peer_photo.cpp │ │ │ ├── api_peer_photo.h │ │ │ ├── api_peer_search.cpp │ │ │ ├── api_peer_search.h │ │ │ ├── api_polls.cpp │ │ │ ├── api_polls.h │ │ │ ├── api_premium.cpp │ │ │ ├── api_premium.h │ │ │ ├── api_premium_option.cpp │ │ │ ├── api_premium_option.h │ │ │ ├── api_reactions_notify_settings.cpp │ │ │ ├── api_reactions_notify_settings.h │ │ │ ├── api_read_metrics.cpp │ │ │ ├── api_read_metrics.h │ │ │ ├── api_report.cpp │ │ │ ├── api_report.h │ │ │ ├── api_ringtones.cpp │ │ │ ├── api_ringtones.h │ │ │ ├── api_self_destruct.cpp │ │ │ ├── api_self_destruct.h │ │ │ ├── api_send_progress.cpp │ │ │ ├── api_send_progress.h │ │ │ ├── api_sending.cpp │ │ │ ├── api_sending.h │ │ │ ├── api_sensitive_content.cpp │ │ │ ├── api_sensitive_content.h │ │ │ ├── api_single_message_search.cpp │ │ │ ├── api_single_message_search.h │ │ │ ├── api_statistics.cpp │ │ │ ├── api_statistics.h │ │ │ ├── api_statistics_data_deserialize.cpp │ │ │ ├── api_statistics_data_deserialize.h │ │ │ ├── api_statistics_sender.cpp │ │ │ ├── api_statistics_sender.h │ │ │ ├── api_suggest_post.cpp │ │ │ ├── api_suggest_post.h │ │ │ ├── api_text_entities.cpp │ │ │ ├── api_text_entities.h │ │ │ ├── api_todo_lists.cpp │ │ │ ├── api_todo_lists.h │ │ │ ├── api_toggling_media.cpp │ │ │ ├── api_toggling_media.h │ │ │ ├── api_transcribes.cpp │ │ │ ├── api_transcribes.h │ │ │ ├── api_unread_things.cpp │ │ │ ├── api_unread_things.h │ │ │ ├── api_updates.cpp │ │ │ ├── api_updates.h │ │ │ ├── api_user_names.cpp │ │ │ ├── api_user_names.h │ │ │ ├── api_user_privacy.cpp │ │ │ ├── api_user_privacy.h │ │ │ ├── api_views.cpp │ │ │ ├── api_views.h │ │ │ ├── api_websites.cpp │ │ │ ├── api_websites.h │ │ │ ├── api_who_reacted.cpp │ │ │ └── api_who_reacted.h │ │ ├── apiwrap.cpp │ │ ├── apiwrap.h │ │ ├── boxes/ │ │ │ ├── about_box.cpp │ │ │ ├── about_box.h │ │ │ ├── about_sponsored_box.cpp │ │ │ ├── about_sponsored_box.h │ │ │ ├── abstract_box.cpp │ │ │ ├── abstract_box.h │ │ │ ├── add_contact_box.cpp │ │ │ ├── add_contact_box.h │ │ │ ├── auto_download_box.cpp │ │ │ ├── auto_download_box.h │ │ │ ├── auto_lock_box.cpp │ │ │ ├── auto_lock_box.h │ │ │ ├── background_box.cpp │ │ │ ├── background_box.h │ │ │ ├── background_preview_box.cpp │ │ │ ├── background_preview_box.h │ │ │ ├── boxes.style │ │ │ ├── choose_filter_box.cpp │ │ │ ├── choose_filter_box.h │ │ │ ├── compose_ai_box.cpp │ │ │ ├── compose_ai_box.h │ │ │ ├── confirm_box.cpp │ │ │ ├── connection_box.cpp │ │ │ ├── connection_box.h │ │ │ ├── contacts_box.cpp │ │ │ ├── create_poll_box.cpp │ │ │ ├── create_poll_box.h │ │ │ ├── delete_messages_box.cpp │ │ │ ├── delete_messages_box.h │ │ │ ├── dictionaries_manager.cpp │ │ │ ├── dictionaries_manager.h │ │ │ ├── download_path_box.cpp │ │ │ ├── download_path_box.h │ │ │ ├── edit_caption_box.cpp │ │ │ ├── edit_caption_box.h │ │ │ ├── edit_privacy_box.cpp │ │ │ ├── edit_privacy_box.h │ │ │ ├── edit_todo_list_box.cpp │ │ │ ├── edit_todo_list_box.h │ │ │ ├── filters/ │ │ │ │ ├── edit_filter_box.cpp │ │ │ │ ├── edit_filter_box.h │ │ │ │ ├── edit_filter_chats_list.cpp │ │ │ │ ├── edit_filter_chats_list.h │ │ │ │ ├── edit_filter_chats_preview.cpp │ │ │ │ ├── edit_filter_chats_preview.h │ │ │ │ ├── edit_filter_links.cpp │ │ │ │ └── edit_filter_links.h │ │ │ ├── gift_credits_box.cpp │ │ │ ├── gift_credits_box.h │ │ │ ├── gift_premium_box.cpp │ │ │ ├── gift_premium_box.h │ │ │ ├── language_box.cpp │ │ │ ├── language_box.h │ │ │ ├── local_storage_box.cpp │ │ │ ├── local_storage_box.h │ │ │ ├── max_invite_box.cpp │ │ │ ├── max_invite_box.h │ │ │ ├── moderate_messages_box.cpp │ │ │ ├── moderate_messages_box.h │ │ │ ├── passcode_box.cpp │ │ │ ├── passcode_box.h │ │ │ ├── peer_list_box.cpp │ │ │ ├── peer_list_box.h │ │ │ ├── peer_list_controllers.cpp │ │ │ ├── peer_list_controllers.h │ │ │ ├── peer_list_widgets.cpp │ │ │ ├── peer_list_widgets.h │ │ │ ├── peer_lists_box.cpp │ │ │ ├── peer_lists_box.h │ │ │ ├── peers/ │ │ │ │ ├── add_bot_to_chat_box.cpp │ │ │ │ ├── add_bot_to_chat_box.h │ │ │ │ ├── add_participants_box.cpp │ │ │ │ ├── add_participants_box.h │ │ │ │ ├── channel_ownership_transfer.cpp │ │ │ │ ├── channel_ownership_transfer.h │ │ │ │ ├── choose_peer_box.cpp │ │ │ │ ├── choose_peer_box.h │ │ │ │ ├── create_managed_bot_box.cpp │ │ │ │ ├── create_managed_bot_box.h │ │ │ │ ├── edit_contact_box.cpp │ │ │ │ ├── edit_contact_box.h │ │ │ │ ├── edit_discussion_link_box.cpp │ │ │ │ ├── edit_discussion_link_box.h │ │ │ │ ├── edit_forum_topic_box.cpp │ │ │ │ ├── edit_forum_topic_box.h │ │ │ │ ├── edit_members_visible.cpp │ │ │ │ ├── edit_members_visible.h │ │ │ │ ├── edit_participant_box.cpp │ │ │ │ ├── edit_participant_box.h │ │ │ │ ├── edit_participants_box.cpp │ │ │ │ ├── edit_participants_box.h │ │ │ │ ├── edit_peer_color_box.cpp │ │ │ │ ├── edit_peer_color_box.h │ │ │ │ ├── edit_peer_common.h │ │ │ │ ├── edit_peer_history_visibility_box.cpp │ │ │ │ ├── edit_peer_history_visibility_box.h │ │ │ │ ├── edit_peer_info_box.cpp │ │ │ │ ├── edit_peer_info_box.h │ │ │ │ ├── edit_peer_invite_link.cpp │ │ │ │ ├── edit_peer_invite_link.h │ │ │ │ ├── edit_peer_invite_links.cpp │ │ │ │ ├── edit_peer_invite_links.h │ │ │ │ ├── edit_peer_permissions_box.cpp │ │ │ │ ├── edit_peer_permissions_box.h │ │ │ │ ├── edit_peer_reactions.cpp │ │ │ │ ├── edit_peer_reactions.h │ │ │ │ ├── edit_peer_requests_box.cpp │ │ │ │ ├── edit_peer_requests_box.h │ │ │ │ ├── edit_peer_type_box.cpp │ │ │ │ ├── edit_peer_type_box.h │ │ │ │ ├── edit_peer_usernames_list.cpp │ │ │ │ ├── edit_peer_usernames_list.h │ │ │ │ ├── edit_tag_control.cpp │ │ │ │ ├── edit_tag_control.h │ │ │ │ ├── peer_short_info_box.cpp │ │ │ │ ├── peer_short_info_box.h │ │ │ │ ├── prepare_short_info_box.cpp │ │ │ │ ├── prepare_short_info_box.h │ │ │ │ ├── replace_boost_box.cpp │ │ │ │ ├── replace_boost_box.h │ │ │ │ ├── tag_info_box.cpp │ │ │ │ ├── tag_info_box.h │ │ │ │ ├── toggle_topics_box.cpp │ │ │ │ ├── toggle_topics_box.h │ │ │ │ ├── verify_peers_box.cpp │ │ │ │ └── verify_peers_box.h │ │ │ ├── phone_banned_box.cpp │ │ │ ├── phone_banned_box.h │ │ │ ├── pin_messages_box.cpp │ │ │ ├── pin_messages_box.h │ │ │ ├── polls.style │ │ │ ├── premium_limits_box.cpp │ │ │ ├── premium_limits_box.h │ │ │ ├── premium_preview_box.cpp │ │ │ ├── premium_preview_box.h │ │ │ ├── reactions_settings_box.cpp │ │ │ ├── reactions_settings_box.h │ │ │ ├── report_messages_box.cpp │ │ │ ├── report_messages_box.h │ │ │ ├── ringtones_box.cpp │ │ │ ├── ringtones_box.h │ │ │ ├── select_future_owner_box.cpp │ │ │ ├── select_future_owner_box.h │ │ │ ├── self_destruction_box.cpp │ │ │ ├── self_destruction_box.h │ │ │ ├── send_credits_box.cpp │ │ │ ├── send_credits_box.h │ │ │ ├── send_files_box.cpp │ │ │ ├── send_files_box.h │ │ │ ├── send_gif_with_caption_box.cpp │ │ │ ├── send_gif_with_caption_box.h │ │ │ ├── share_box.cpp │ │ │ ├── share_box.h │ │ │ ├── star_gift_auction_box.cpp │ │ │ ├── star_gift_auction_box.h │ │ │ ├── star_gift_box.cpp │ │ │ ├── star_gift_box.h │ │ │ ├── star_gift_cover_box.cpp │ │ │ ├── star_gift_cover_box.h │ │ │ ├── star_gift_craft_animation.cpp │ │ │ ├── star_gift_craft_animation.h │ │ │ ├── star_gift_craft_box.cpp │ │ │ ├── star_gift_craft_box.h │ │ │ ├── star_gift_preview_box.cpp │ │ │ ├── star_gift_preview_box.h │ │ │ ├── star_gift_resale_box.cpp │ │ │ ├── star_gift_resale_box.h │ │ │ ├── sticker_set_box.cpp │ │ │ ├── sticker_set_box.h │ │ │ ├── stickers_box.cpp │ │ │ ├── stickers_box.h │ │ │ ├── transfer_gift_box.cpp │ │ │ ├── transfer_gift_box.h │ │ │ ├── translate_box.cpp │ │ │ ├── translate_box.h │ │ │ ├── translate_box_content.cpp │ │ │ ├── translate_box_content.h │ │ │ ├── url_auth_box.cpp │ │ │ ├── url_auth_box.h │ │ │ ├── url_auth_box_content.cpp │ │ │ ├── url_auth_box_content.h │ │ │ ├── username_box.cpp │ │ │ └── username_box.h │ │ ├── calls/ │ │ │ ├── calls.style │ │ │ ├── calls_box_controller.cpp │ │ │ ├── calls_box_controller.h │ │ │ ├── calls_call.cpp │ │ │ ├── calls_call.h │ │ │ ├── calls_controller.cpp │ │ │ ├── calls_controller.h │ │ │ ├── calls_controller_tgvoip.h │ │ │ ├── calls_controller_webrtc.cpp │ │ │ ├── calls_controller_webrtc.h │ │ │ ├── calls_emoji_fingerprint.cpp │ │ │ ├── calls_emoji_fingerprint.h │ │ │ ├── calls_instance.cpp │ │ │ ├── calls_instance.h │ │ │ ├── calls_panel.cpp │ │ │ ├── calls_panel.h │ │ │ ├── calls_panel_background.cpp │ │ │ ├── calls_panel_background.h │ │ │ ├── calls_signal_bars.cpp │ │ │ ├── calls_signal_bars.h │ │ │ ├── calls_top_bar.cpp │ │ │ ├── calls_top_bar.h │ │ │ ├── calls_userpic.cpp │ │ │ ├── calls_userpic.h │ │ │ ├── calls_video_bubble.cpp │ │ │ ├── calls_video_bubble.h │ │ │ ├── calls_video_incoming.cpp │ │ │ ├── calls_video_incoming.h │ │ │ ├── calls_window.cpp │ │ │ ├── calls_window.h │ │ │ ├── group/ │ │ │ │ ├── calls_choose_join_as.cpp │ │ │ │ ├── calls_choose_join_as.h │ │ │ │ ├── calls_cover_item.cpp │ │ │ │ ├── calls_cover_item.h │ │ │ │ ├── calls_group_call.cpp │ │ │ │ ├── calls_group_call.h │ │ │ │ ├── calls_group_common.cpp │ │ │ │ ├── calls_group_common.h │ │ │ │ ├── calls_group_invite_controller.cpp │ │ │ │ ├── calls_group_invite_controller.h │ │ │ │ ├── calls_group_members.cpp │ │ │ │ ├── calls_group_members.h │ │ │ │ ├── calls_group_members_row.cpp │ │ │ │ ├── calls_group_members_row.h │ │ │ │ ├── calls_group_menu.cpp │ │ │ │ ├── calls_group_menu.h │ │ │ │ ├── calls_group_message_encryption.cpp │ │ │ │ ├── calls_group_message_encryption.h │ │ │ │ ├── calls_group_message_field.cpp │ │ │ │ ├── calls_group_message_field.h │ │ │ │ ├── calls_group_messages.cpp │ │ │ │ ├── calls_group_messages.h │ │ │ │ ├── calls_group_messages_ui.cpp │ │ │ │ ├── calls_group_messages_ui.h │ │ │ │ ├── calls_group_panel.cpp │ │ │ │ ├── calls_group_panel.h │ │ │ │ ├── calls_group_rtmp.cpp │ │ │ │ ├── calls_group_rtmp.h │ │ │ │ ├── calls_group_settings.cpp │ │ │ │ ├── calls_group_settings.h │ │ │ │ ├── calls_group_stars_box.cpp │ │ │ │ ├── calls_group_stars_box.h │ │ │ │ ├── calls_group_toasts.cpp │ │ │ │ ├── calls_group_toasts.h │ │ │ │ ├── calls_group_viewport.cpp │ │ │ │ ├── calls_group_viewport.h │ │ │ │ ├── calls_group_viewport_opengl.cpp │ │ │ │ ├── calls_group_viewport_opengl.h │ │ │ │ ├── calls_group_viewport_raster.cpp │ │ │ │ ├── calls_group_viewport_raster.h │ │ │ │ ├── calls_group_viewport_rhi.cpp │ │ │ │ ├── calls_group_viewport_rhi.h │ │ │ │ ├── calls_group_viewport_tile.cpp │ │ │ │ ├── calls_group_viewport_tile.h │ │ │ │ ├── calls_volume_item.cpp │ │ │ │ ├── calls_volume_item.h │ │ │ │ └── ui/ │ │ │ │ ├── calls_group_recording_box.cpp │ │ │ │ ├── calls_group_recording_box.h │ │ │ │ ├── calls_group_scheduled_labels.cpp │ │ │ │ ├── calls_group_scheduled_labels.h │ │ │ │ ├── calls_group_stars_coloring.cpp │ │ │ │ ├── calls_group_stars_coloring.h │ │ │ │ ├── desktop_capture_choose_source.cpp │ │ │ │ └── desktop_capture_choose_source.h │ │ │ └── ui/ │ │ │ ├── calls_device_menu.cpp │ │ │ └── calls_device_menu.h │ │ ├── chat_helpers/ │ │ │ ├── bot_command.cpp │ │ │ ├── bot_command.h │ │ │ ├── bot_keyboard.cpp │ │ │ ├── bot_keyboard.h │ │ │ ├── chat_helpers.style │ │ │ ├── compose/ │ │ │ │ ├── compose_features.h │ │ │ │ ├── compose_show.cpp │ │ │ │ └── compose_show.h │ │ │ ├── emoji_interactions.cpp │ │ │ ├── emoji_interactions.h │ │ │ ├── emoji_keywords.cpp │ │ │ ├── emoji_keywords.h │ │ │ ├── emoji_list_widget.cpp │ │ │ ├── emoji_list_widget.h │ │ │ ├── emoji_sets_manager.cpp │ │ │ ├── emoji_sets_manager.h │ │ │ ├── emoji_suggestions_widget.cpp │ │ │ ├── emoji_suggestions_widget.h │ │ │ ├── field_autocomplete.cpp │ │ │ ├── field_autocomplete.h │ │ │ ├── field_characters_count_manager.cpp │ │ │ ├── field_characters_count_manager.h │ │ │ ├── gifs_list_widget.cpp │ │ │ ├── gifs_list_widget.h │ │ │ ├── message_field.cpp │ │ │ ├── message_field.h │ │ │ ├── share_message_phrase_factory.cpp │ │ │ ├── share_message_phrase_factory.h │ │ │ ├── spellchecker_common.cpp │ │ │ ├── spellchecker_common.h │ │ │ ├── stickers_dice_pack.cpp │ │ │ ├── stickers_dice_pack.h │ │ │ ├── stickers_emoji_image_loader.cpp │ │ │ ├── stickers_emoji_image_loader.h │ │ │ ├── stickers_emoji_pack.cpp │ │ │ ├── stickers_emoji_pack.h │ │ │ ├── stickers_gift_box_pack.cpp │ │ │ ├── stickers_gift_box_pack.h │ │ │ ├── stickers_list_footer.cpp │ │ │ ├── stickers_list_footer.h │ │ │ ├── stickers_list_widget.cpp │ │ │ ├── stickers_list_widget.h │ │ │ ├── stickers_lottie.cpp │ │ │ ├── stickers_lottie.h │ │ │ ├── tabbed_panel.cpp │ │ │ ├── tabbed_panel.h │ │ │ ├── tabbed_section.cpp │ │ │ ├── tabbed_section.h │ │ │ ├── tabbed_selector.cpp │ │ │ ├── tabbed_selector.h │ │ │ ├── ttl_media_layer_widget.cpp │ │ │ └── ttl_media_layer_widget.h │ │ ├── codegen/ │ │ │ └── scheme/ │ │ │ └── codegen_scheme.py │ │ ├── config.h │ │ ├── core/ │ │ │ ├── application.cpp │ │ │ ├── application.h │ │ │ ├── bank_card_click_handler.cpp │ │ │ ├── bank_card_click_handler.h │ │ │ ├── base_integration.cpp │ │ │ ├── base_integration.h │ │ │ ├── cached_webview_availability.h │ │ │ ├── changelogs.cpp │ │ │ ├── changelogs.h │ │ │ ├── click_handler_types.cpp │ │ │ ├── click_handler_types.h │ │ │ ├── core_cloud_password.cpp │ │ │ ├── core_cloud_password.h │ │ │ ├── core_settings.cpp │ │ │ ├── core_settings.h │ │ │ ├── core_settings_proxy.cpp │ │ │ ├── core_settings_proxy.h │ │ │ ├── crash_report_window.cpp │ │ │ ├── crash_report_window.h │ │ │ ├── crash_reports.cpp │ │ │ ├── crash_reports.h │ │ │ ├── credits_amount.h │ │ │ ├── current_geo_location.cpp │ │ │ ├── current_geo_location.h │ │ │ ├── deadlock_detector.h │ │ │ ├── deep_links/ │ │ │ │ ├── deep_links_chats.cpp │ │ │ │ ├── deep_links_chats.h │ │ │ │ ├── deep_links_contacts.cpp │ │ │ │ ├── deep_links_contacts.h │ │ │ │ ├── deep_links_new.cpp │ │ │ │ ├── deep_links_new.h │ │ │ │ ├── deep_links_router.cpp │ │ │ │ ├── deep_links_router.h │ │ │ │ ├── deep_links_settings.cpp │ │ │ │ ├── deep_links_settings.h │ │ │ │ └── deep_links_types.h │ │ │ ├── file_location.cpp │ │ │ ├── file_location.h │ │ │ ├── file_utilities.cpp │ │ │ ├── file_utilities.h │ │ │ ├── fork_settings.cpp │ │ │ ├── fork_settings.h │ │ │ ├── launcher.cpp │ │ │ ├── launcher.h │ │ │ ├── local_url_handlers.cpp │ │ │ ├── local_url_handlers.h │ │ │ ├── mime_type.cpp │ │ │ ├── mime_type.h │ │ │ ├── phone_click_handler.cpp │ │ │ ├── phone_click_handler.h │ │ │ ├── sandbox.cpp │ │ │ ├── sandbox.h │ │ │ ├── shortcuts.cpp │ │ │ ├── shortcuts.h │ │ │ ├── ui_integration.cpp │ │ │ ├── ui_integration.h │ │ │ ├── update_checker.cpp │ │ │ ├── update_checker.h │ │ │ ├── utils.cpp │ │ │ ├── utils.h │ │ │ └── version.h │ │ ├── countries/ │ │ │ ├── countries_instance.cpp │ │ │ ├── countries_instance.h │ │ │ ├── countries_manager.cpp │ │ │ └── countries_manager.h │ │ ├── data/ │ │ │ ├── business/ │ │ │ │ ├── data_business_chatbots.cpp │ │ │ │ ├── data_business_chatbots.h │ │ │ │ ├── data_business_common.cpp │ │ │ │ ├── data_business_common.h │ │ │ │ ├── data_business_info.cpp │ │ │ │ ├── data_business_info.h │ │ │ │ ├── data_shortcut_messages.cpp │ │ │ │ └── data_shortcut_messages.h │ │ │ ├── components/ │ │ │ │ ├── credits.cpp │ │ │ │ ├── credits.h │ │ │ │ ├── factchecks.cpp │ │ │ │ ├── factchecks.h │ │ │ │ ├── gift_auctions.cpp │ │ │ │ ├── gift_auctions.h │ │ │ │ ├── location_pickers.cpp │ │ │ │ ├── location_pickers.h │ │ │ │ ├── passkeys.cpp │ │ │ │ ├── passkeys.h │ │ │ │ ├── promo_suggestions.cpp │ │ │ │ ├── promo_suggestions.h │ │ │ │ ├── recent_peers.cpp │ │ │ │ ├── recent_peers.h │ │ │ │ ├── recent_shared_media_gifts.cpp │ │ │ │ ├── recent_shared_media_gifts.h │ │ │ │ ├── scheduled_messages.cpp │ │ │ │ ├── scheduled_messages.h │ │ │ │ ├── sponsored_messages.cpp │ │ │ │ ├── sponsored_messages.h │ │ │ │ ├── top_peers.cpp │ │ │ │ └── top_peers.h │ │ │ ├── data_abstract_sparse_ids.h │ │ │ ├── data_abstract_structure.cpp │ │ │ ├── data_abstract_structure.h │ │ │ ├── data_audio_msg_id.cpp │ │ │ ├── data_audio_msg_id.h │ │ │ ├── data_authorization.h │ │ │ ├── data_auto_download.cpp │ │ │ ├── data_auto_download.h │ │ │ ├── data_birthday.cpp │ │ │ ├── data_birthday.h │ │ │ ├── data_boosts.h │ │ │ ├── data_bot_app.cpp │ │ │ ├── data_bot_app.h │ │ │ ├── data_changes.cpp │ │ │ ├── data_changes.h │ │ │ ├── data_channel.cpp │ │ │ ├── data_channel.h │ │ │ ├── data_channel_admins.cpp │ │ │ ├── data_channel_admins.h │ │ │ ├── data_channel_earn.h │ │ │ ├── data_chat.cpp │ │ │ ├── data_chat.h │ │ │ ├── data_chat_filters.cpp │ │ │ ├── data_chat_filters.h │ │ │ ├── data_chat_participant_status.cpp │ │ │ ├── data_chat_participant_status.h │ │ │ ├── data_cloud_file.cpp │ │ │ ├── data_cloud_file.h │ │ │ ├── data_cloud_themes.cpp │ │ │ ├── data_cloud_themes.h │ │ │ ├── data_credits.h │ │ │ ├── data_credits_earn.h │ │ │ ├── data_document.cpp │ │ │ ├── data_document.h │ │ │ ├── data_document_media.cpp │ │ │ ├── data_document_media.h │ │ │ ├── data_document_resolver.cpp │ │ │ ├── data_document_resolver.h │ │ │ ├── data_download_manager.cpp │ │ │ ├── data_download_manager.h │ │ │ ├── data_drafts.cpp │ │ │ ├── data_drafts.h │ │ │ ├── data_emoji_statuses.cpp │ │ │ ├── data_emoji_statuses.h │ │ │ ├── data_file_click_handler.cpp │ │ │ ├── data_file_click_handler.h │ │ │ ├── data_file_origin.cpp │ │ │ ├── data_file_origin.h │ │ │ ├── data_flags.h │ │ │ ├── data_folder.cpp │ │ │ ├── data_folder.h │ │ │ ├── data_forum.cpp │ │ │ ├── data_forum.h │ │ │ ├── data_forum_icons.cpp │ │ │ ├── data_forum_icons.h │ │ │ ├── data_forum_topic.cpp │ │ │ ├── data_forum_topic.h │ │ │ ├── data_game.cpp │ │ │ ├── data_game.h │ │ │ ├── data_group_call.cpp │ │ │ ├── data_group_call.h │ │ │ ├── data_groups.cpp │ │ │ ├── data_groups.h │ │ │ ├── data_histories.cpp │ │ │ ├── data_histories.h │ │ │ ├── data_history_messages.cpp │ │ │ ├── data_history_messages.h │ │ │ ├── data_lastseen_status.h │ │ │ ├── data_location.cpp │ │ │ ├── data_location.h │ │ │ ├── data_media_preload.cpp │ │ │ ├── data_media_preload.h │ │ │ ├── data_media_rotation.cpp │ │ │ ├── data_media_rotation.h │ │ │ ├── data_media_types.cpp │ │ │ ├── data_media_types.h │ │ │ ├── data_message_reaction_id.cpp │ │ │ ├── data_message_reaction_id.h │ │ │ ├── data_message_reactions.cpp │ │ │ ├── data_message_reactions.h │ │ │ ├── data_messages.cpp │ │ │ ├── data_messages.h │ │ │ ├── data_msg_id.h │ │ │ ├── data_passkey_deserialize.cpp │ │ │ ├── data_passkey_deserialize.h │ │ │ ├── data_peer.cpp │ │ │ ├── data_peer.h │ │ │ ├── data_peer_bot_command.cpp │ │ │ ├── data_peer_bot_command.h │ │ │ ├── data_peer_bot_commands.cpp │ │ │ ├── data_peer_bot_commands.h │ │ │ ├── data_peer_colors.h │ │ │ ├── data_peer_common.h │ │ │ ├── data_peer_id.cpp │ │ │ ├── data_peer_id.h │ │ │ ├── data_peer_values.cpp │ │ │ ├── data_peer_values.h │ │ │ ├── data_photo.cpp │ │ │ ├── data_photo.h │ │ │ ├── data_photo_media.cpp │ │ │ ├── data_photo_media.h │ │ │ ├── data_poll.cpp │ │ │ ├── data_poll.h │ │ │ ├── data_poll_messages.cpp │ │ │ ├── data_poll_messages.h │ │ │ ├── data_premium_limits.cpp │ │ │ ├── data_premium_limits.h │ │ │ ├── data_premium_subscription_option.h │ │ │ ├── data_pts_waiter.cpp │ │ │ ├── data_pts_waiter.h │ │ │ ├── data_replies_list.cpp │ │ │ ├── data_replies_list.h │ │ │ ├── data_reply_preview.cpp │ │ │ ├── data_reply_preview.h │ │ │ ├── data_report.h │ │ │ ├── data_saved_messages.cpp │ │ │ ├── data_saved_messages.h │ │ │ ├── data_saved_music.cpp │ │ │ ├── data_saved_music.h │ │ │ ├── data_saved_sublist.cpp │ │ │ ├── data_saved_sublist.h │ │ │ ├── data_search_calendar.cpp │ │ │ ├── data_search_calendar.h │ │ │ ├── data_search_controller.cpp │ │ │ ├── data_search_controller.h │ │ │ ├── data_send_action.cpp │ │ │ ├── data_send_action.h │ │ │ ├── data_session.cpp │ │ │ ├── data_session.h │ │ │ ├── data_shared_media.cpp │ │ │ ├── data_shared_media.h │ │ │ ├── data_sparse_ids.cpp │ │ │ ├── data_sparse_ids.h │ │ │ ├── data_star_gift.cpp │ │ │ ├── data_star_gift.h │ │ │ ├── data_statistics.h │ │ │ ├── data_statistics_chart.cpp │ │ │ ├── data_statistics_chart.h │ │ │ ├── data_stories.cpp │ │ │ ├── data_stories.h │ │ │ ├── data_stories_ids.cpp │ │ │ ├── data_stories_ids.h │ │ │ ├── data_story.cpp │ │ │ ├── data_story.h │ │ │ ├── data_streaming.cpp │ │ │ ├── data_streaming.h │ │ │ ├── data_subscriptions.h │ │ │ ├── data_thread.cpp │ │ │ ├── data_thread.h │ │ │ ├── data_todo_list.cpp │ │ │ ├── data_todo_list.h │ │ │ ├── data_types.cpp │ │ │ ├── data_types.h │ │ │ ├── data_unread_value.cpp │ │ │ ├── data_unread_value.h │ │ │ ├── data_user.cpp │ │ │ ├── data_user.h │ │ │ ├── data_user_names.cpp │ │ │ ├── data_user_names.h │ │ │ ├── data_user_photos.cpp │ │ │ ├── data_user_photos.h │ │ │ ├── data_wall_paper.cpp │ │ │ ├── data_wall_paper.h │ │ │ ├── data_web_page.cpp │ │ │ ├── data_web_page.h │ │ │ ├── notify/ │ │ │ │ ├── data_notify_settings.cpp │ │ │ │ ├── data_notify_settings.h │ │ │ │ ├── data_peer_notify_settings.cpp │ │ │ │ ├── data_peer_notify_settings.h │ │ │ │ ├── data_peer_notify_volume.cpp │ │ │ │ └── data_peer_notify_volume.h │ │ │ ├── raw/ │ │ │ │ ├── raw_countries_bounds.cpp │ │ │ │ └── raw_countries_bounds.h │ │ │ └── stickers/ │ │ │ ├── data_custom_emoji.cpp │ │ │ ├── data_custom_emoji.h │ │ │ ├── data_stickers.cpp │ │ │ ├── data_stickers.h │ │ │ ├── data_stickers_set.cpp │ │ │ └── data_stickers_set.h │ │ ├── dialogs/ │ │ │ ├── dialogs.style │ │ │ ├── dialogs_common.h │ │ │ ├── dialogs_entry.cpp │ │ │ ├── dialogs_entry.h │ │ │ ├── dialogs_indexed_list.cpp │ │ │ ├── dialogs_indexed_list.h │ │ │ ├── dialogs_inner_widget.cpp │ │ │ ├── dialogs_inner_widget.h │ │ │ ├── dialogs_key.cpp │ │ │ ├── dialogs_key.h │ │ │ ├── dialogs_list.cpp │ │ │ ├── dialogs_list.h │ │ │ ├── dialogs_main_list.cpp │ │ │ ├── dialogs_main_list.h │ │ │ ├── dialogs_pinned_list.cpp │ │ │ ├── dialogs_pinned_list.h │ │ │ ├── dialogs_quick_action.cpp │ │ │ ├── dialogs_quick_action.h │ │ │ ├── dialogs_row.cpp │ │ │ ├── dialogs_row.h │ │ │ ├── dialogs_search_from_controllers.cpp │ │ │ ├── dialogs_search_from_controllers.h │ │ │ ├── dialogs_search_posts.cpp │ │ │ ├── dialogs_search_posts.h │ │ │ ├── dialogs_search_tags.cpp │ │ │ ├── dialogs_search_tags.h │ │ │ ├── dialogs_three_state_icon.h │ │ │ ├── dialogs_top_bar_suggestion.cpp │ │ │ ├── dialogs_top_bar_suggestion.h │ │ │ ├── dialogs_widget.cpp │ │ │ ├── dialogs_widget.h │ │ │ └── ui/ │ │ │ ├── chat_search_empty.cpp │ │ │ ├── chat_search_empty.h │ │ │ ├── chat_search_in.cpp │ │ │ ├── chat_search_in.h │ │ │ ├── dialogs_layout.cpp │ │ │ ├── dialogs_layout.h │ │ │ ├── dialogs_message_view.cpp │ │ │ ├── dialogs_message_view.h │ │ │ ├── dialogs_quick_action.h │ │ │ ├── dialogs_quick_action_context.h │ │ │ ├── dialogs_stories_content.cpp │ │ │ ├── dialogs_stories_content.h │ │ │ ├── dialogs_stories_list.cpp │ │ │ ├── dialogs_stories_list.h │ │ │ ├── dialogs_suggestions.cpp │ │ │ ├── dialogs_suggestions.h │ │ │ ├── dialogs_top_bar_suggestion_content.cpp │ │ │ ├── dialogs_top_bar_suggestion_content.h │ │ │ ├── dialogs_topics_view.cpp │ │ │ ├── dialogs_topics_view.h │ │ │ ├── dialogs_video_userpic.cpp │ │ │ ├── dialogs_video_userpic.h │ │ │ ├── posts_search_intro.cpp │ │ │ ├── posts_search_intro.h │ │ │ ├── top_peers_strip.cpp │ │ │ └── top_peers_strip.h │ │ ├── editor/ │ │ │ ├── color_picker.cpp │ │ │ ├── color_picker.h │ │ │ ├── controllers/ │ │ │ │ ├── controllers.h │ │ │ │ ├── stickers_panel_controller.cpp │ │ │ │ ├── stickers_panel_controller.h │ │ │ │ ├── undo_controller.cpp │ │ │ │ └── undo_controller.h │ │ │ ├── editor.style │ │ │ ├── editor_crop.cpp │ │ │ ├── editor_crop.h │ │ │ ├── editor_layer_widget.cpp │ │ │ ├── editor_layer_widget.h │ │ │ ├── editor_paint.cpp │ │ │ ├── editor_paint.h │ │ │ ├── photo_editor.cpp │ │ │ ├── photo_editor.h │ │ │ ├── photo_editor_common.cpp │ │ │ ├── photo_editor_common.h │ │ │ ├── photo_editor_content.cpp │ │ │ ├── photo_editor_content.h │ │ │ ├── photo_editor_controls.cpp │ │ │ ├── photo_editor_controls.h │ │ │ ├── photo_editor_inner_common.h │ │ │ ├── photo_editor_layer_widget.cpp │ │ │ ├── photo_editor_layer_widget.h │ │ │ └── scene/ │ │ │ ├── scene.cpp │ │ │ ├── scene.h │ │ │ ├── scene_item_base.cpp │ │ │ ├── scene_item_base.h │ │ │ ├── scene_item_canvas.cpp │ │ │ ├── scene_item_canvas.h │ │ │ ├── scene_item_image.cpp │ │ │ ├── scene_item_image.h │ │ │ ├── scene_item_line.cpp │ │ │ ├── scene_item_line.h │ │ │ ├── scene_item_sticker.cpp │ │ │ └── scene_item_sticker.h │ │ ├── export/ │ │ │ ├── data/ │ │ │ │ ├── export_data_types.cpp │ │ │ │ └── export_data_types.h │ │ │ ├── export_api_wrap.cpp │ │ │ ├── export_api_wrap.h │ │ │ ├── export_controller.cpp │ │ │ ├── export_controller.h │ │ │ ├── export_manager.cpp │ │ │ ├── export_manager.h │ │ │ ├── export_pch.h │ │ │ ├── export_settings.cpp │ │ │ ├── export_settings.h │ │ │ ├── output/ │ │ │ │ ├── export_output_abstract.cpp │ │ │ │ ├── export_output_abstract.h │ │ │ │ ├── export_output_file.cpp │ │ │ │ ├── export_output_file.h │ │ │ │ ├── export_output_html.cpp │ │ │ │ ├── export_output_html.h │ │ │ │ ├── export_output_html_and_json.cpp │ │ │ │ ├── export_output_html_and_json.h │ │ │ │ ├── export_output_json.cpp │ │ │ │ ├── export_output_json.h │ │ │ │ ├── export_output_result.h │ │ │ │ ├── export_output_stats.cpp │ │ │ │ └── export_output_stats.h │ │ │ └── view/ │ │ │ ├── export.style │ │ │ ├── export_view_content.cpp │ │ │ ├── export_view_content.h │ │ │ ├── export_view_panel_controller.cpp │ │ │ ├── export_view_panel_controller.h │ │ │ ├── export_view_progress.cpp │ │ │ ├── export_view_progress.h │ │ │ ├── export_view_settings.cpp │ │ │ ├── export_view_settings.h │ │ │ ├── export_view_top_bar.cpp │ │ │ └── export_view_top_bar.h │ │ ├── ffmpeg/ │ │ │ ├── ffmpeg_bytes_io_wrap.h │ │ │ ├── ffmpeg_frame_generator.cpp │ │ │ ├── ffmpeg_frame_generator.h │ │ │ ├── ffmpeg_utility.cpp │ │ │ └── ffmpeg_utility.h │ │ ├── forkgram/ │ │ │ ├── gpu_demo_renderer.cpp │ │ │ ├── gpu_demo_renderer.h │ │ │ ├── uri_menu.cpp │ │ │ ├── uri_menu.h │ │ │ ├── uri_open.cpp │ │ │ └── uri_open.h │ │ ├── history/ │ │ │ ├── admin_log/ │ │ │ │ ├── history_admin_log_filter.cpp │ │ │ │ ├── history_admin_log_filter.h │ │ │ │ ├── history_admin_log_filter_value.h │ │ │ │ ├── history_admin_log_inner.cpp │ │ │ │ ├── history_admin_log_inner.h │ │ │ │ ├── history_admin_log_item.cpp │ │ │ │ ├── history_admin_log_item.h │ │ │ │ ├── history_admin_log_section.cpp │ │ │ │ └── history_admin_log_section.h │ │ │ ├── history.cpp │ │ │ ├── history.h │ │ │ ├── history_drag_area.cpp │ │ │ ├── history_drag_area.h │ │ │ ├── history_inner_widget.cpp │ │ │ ├── history_inner_widget.h │ │ │ ├── history_item.cpp │ │ │ ├── history_item.h │ │ │ ├── history_item_components.cpp │ │ │ ├── history_item_components.h │ │ │ ├── history_item_edition.cpp │ │ │ ├── history_item_edition.h │ │ │ ├── history_item_helpers.cpp │ │ │ ├── history_item_helpers.h │ │ │ ├── history_item_reply_markup.cpp │ │ │ ├── history_item_reply_markup.h │ │ │ ├── history_item_text.cpp │ │ │ ├── history_item_text.h │ │ │ ├── history_location_manager.cpp │ │ │ ├── history_location_manager.h │ │ │ ├── history_message.cpp │ │ │ ├── history_streamed_drafts.cpp │ │ │ ├── history_streamed_drafts.h │ │ │ ├── history_translation.cpp │ │ │ ├── history_translation.h │ │ │ ├── history_unread_things.cpp │ │ │ ├── history_unread_things.h │ │ │ ├── history_view_highlight_manager.cpp │ │ │ ├── history_view_highlight_manager.h │ │ │ ├── history_view_swipe_back_session.cpp │ │ │ ├── history_view_swipe_back_session.h │ │ │ ├── history_view_top_toast.cpp │ │ │ ├── history_view_top_toast.h │ │ │ ├── history_widget.cpp │ │ │ ├── history_widget.h │ │ │ └── view/ │ │ │ ├── controls/ │ │ │ │ ├── compose_controls_common.h │ │ │ │ ├── history_view_characters_limit.cpp │ │ │ │ ├── history_view_characters_limit.h │ │ │ │ ├── history_view_compose_ai_button.cpp │ │ │ │ ├── history_view_compose_ai_button.h │ │ │ │ ├── history_view_compose_ai_tooltip.cpp │ │ │ │ ├── history_view_compose_ai_tooltip.h │ │ │ │ ├── history_view_compose_controls.cpp │ │ │ │ ├── history_view_compose_controls.h │ │ │ │ ├── history_view_compose_media_edit_manager.cpp │ │ │ │ ├── history_view_compose_media_edit_manager.h │ │ │ │ ├── history_view_compose_search.cpp │ │ │ │ ├── history_view_compose_search.h │ │ │ │ ├── history_view_draft_options.cpp │ │ │ │ ├── history_view_draft_options.h │ │ │ │ ├── history_view_forward_panel.cpp │ │ │ │ ├── history_view_forward_panel.h │ │ │ │ ├── history_view_suggest_options.cpp │ │ │ │ ├── history_view_suggest_options.h │ │ │ │ ├── history_view_ttl_button.cpp │ │ │ │ ├── history_view_ttl_button.h │ │ │ │ ├── history_view_voice_record_bar.cpp │ │ │ │ ├── history_view_voice_record_bar.h │ │ │ │ ├── history_view_voice_record_button.cpp │ │ │ │ ├── history_view_voice_record_button.h │ │ │ │ ├── history_view_webpage_processor.cpp │ │ │ │ └── history_view_webpage_processor.h │ │ │ ├── history_view_about_view.cpp │ │ │ ├── history_view_about_view.h │ │ │ ├── history_view_add_poll_option.cpp │ │ │ ├── history_view_add_poll_option.h │ │ │ ├── history_view_bottom_info.cpp │ │ │ ├── history_view_bottom_info.h │ │ │ ├── history_view_chat_preview.cpp │ │ │ ├── history_view_chat_preview.h │ │ │ ├── history_view_chat_section.cpp │ │ │ ├── history_view_chat_section.h │ │ │ ├── history_view_contact_status.cpp │ │ │ ├── history_view_contact_status.h │ │ │ ├── history_view_context_menu.cpp │ │ │ ├── history_view_context_menu.h │ │ │ ├── history_view_context_menu_fork.cpp │ │ │ ├── history_view_context_menu_fork.h │ │ │ ├── history_view_corner_buttons.cpp │ │ │ ├── history_view_corner_buttons.h │ │ │ ├── history_view_cursor_state.cpp │ │ │ ├── history_view_cursor_state.h │ │ │ ├── history_view_draw_to_reply.cpp │ │ │ ├── history_view_draw_to_reply.h │ │ │ ├── history_view_element.cpp │ │ │ ├── history_view_element.h │ │ │ ├── history_view_element_overlay.cpp │ │ │ ├── history_view_element_overlay.h │ │ │ ├── history_view_emoji_interactions.cpp │ │ │ ├── history_view_emoji_interactions.h │ │ │ ├── history_view_empty_list_bubble.cpp │ │ │ ├── history_view_empty_list_bubble.h │ │ │ ├── history_view_fake_items.cpp │ │ │ ├── history_view_fake_items.h │ │ │ ├── history_view_group_call_bar.cpp │ │ │ ├── history_view_group_call_bar.h │ │ │ ├── history_view_group_members_widget.cpp │ │ │ ├── history_view_group_members_widget.h │ │ │ ├── history_view_item_preview.h │ │ │ ├── history_view_list_widget.cpp │ │ │ ├── history_view_list_widget.h │ │ │ ├── history_view_message.cpp │ │ │ ├── history_view_message.h │ │ │ ├── history_view_object.h │ │ │ ├── history_view_paid_reaction_toast.cpp │ │ │ ├── history_view_paid_reaction_toast.h │ │ │ ├── history_view_pinned_bar.cpp │ │ │ ├── history_view_pinned_bar.h │ │ │ ├── history_view_pinned_section.cpp │ │ │ ├── history_view_pinned_section.h │ │ │ ├── history_view_pinned_tracker.cpp │ │ │ ├── history_view_pinned_tracker.h │ │ │ ├── history_view_quick_action.cpp │ │ │ ├── history_view_quick_action.h │ │ │ ├── history_view_reaction_preview.cpp │ │ │ ├── history_view_reaction_preview.h │ │ │ ├── history_view_read_metrics_tracker.cpp │ │ │ ├── history_view_read_metrics_tracker.h │ │ │ ├── history_view_reply.cpp │ │ │ ├── history_view_reply.h │ │ │ ├── history_view_reply_button.cpp │ │ │ ├── history_view_reply_button.h │ │ │ ├── history_view_requests_bar.cpp │ │ │ ├── history_view_requests_bar.h │ │ │ ├── history_view_schedule_box.cpp │ │ │ ├── history_view_schedule_box.h │ │ │ ├── history_view_scheduled_section.cpp │ │ │ ├── history_view_scheduled_section.h │ │ │ ├── history_view_self_forwards_tagger.cpp │ │ │ ├── history_view_self_forwards_tagger.h │ │ │ ├── history_view_send_action.cpp │ │ │ ├── history_view_send_action.h │ │ │ ├── history_view_service_message.cpp │ │ │ ├── history_view_service_message.h │ │ │ ├── history_view_sponsored_click_handler.cpp │ │ │ ├── history_view_sponsored_click_handler.h │ │ │ ├── history_view_sticker_toast.cpp │ │ │ ├── history_view_sticker_toast.h │ │ │ ├── history_view_subsection_tabs.cpp │ │ │ ├── history_view_subsection_tabs.h │ │ │ ├── history_view_summary_header.cpp │ │ │ ├── history_view_summary_header.h │ │ │ ├── history_view_text_helper.cpp │ │ │ ├── history_view_text_helper.h │ │ │ ├── history_view_top_bar_widget.cpp │ │ │ ├── history_view_top_bar_widget.h │ │ │ ├── history_view_top_peers_selector.cpp │ │ │ ├── history_view_top_peers_selector.h │ │ │ ├── history_view_transcribe_button.cpp │ │ │ ├── history_view_transcribe_button.h │ │ │ ├── history_view_translate_bar.cpp │ │ │ ├── history_view_translate_bar.h │ │ │ ├── history_view_translate_tracker.cpp │ │ │ ├── history_view_translate_tracker.h │ │ │ ├── history_view_view_button.cpp │ │ │ ├── history_view_view_button.h │ │ │ ├── history_view_webpage_preview.cpp │ │ │ ├── history_view_webpage_preview.h │ │ │ ├── media/ │ │ │ │ ├── history_view_birthday_suggestion.cpp │ │ │ │ ├── history_view_birthday_suggestion.h │ │ │ │ ├── history_view_call.cpp │ │ │ │ ├── history_view_call.h │ │ │ │ ├── history_view_contact.cpp │ │ │ │ ├── history_view_contact.h │ │ │ │ ├── history_view_custom_emoji.cpp │ │ │ │ ├── history_view_custom_emoji.h │ │ │ │ ├── history_view_dice.cpp │ │ │ │ ├── history_view_dice.h │ │ │ │ ├── history_view_document.cpp │ │ │ │ ├── history_view_document.h │ │ │ │ ├── history_view_file.cpp │ │ │ │ ├── history_view_file.h │ │ │ │ ├── history_view_game.cpp │ │ │ │ ├── history_view_game.h │ │ │ │ ├── history_view_gif.cpp │ │ │ │ ├── history_view_gif.h │ │ │ │ ├── history_view_giveaway.cpp │ │ │ │ ├── history_view_giveaway.h │ │ │ │ ├── history_view_invoice.cpp │ │ │ │ ├── history_view_invoice.h │ │ │ │ ├── history_view_large_emoji.cpp │ │ │ │ ├── history_view_large_emoji.h │ │ │ │ ├── history_view_location.cpp │ │ │ │ ├── history_view_location.h │ │ │ │ ├── history_view_media.cpp │ │ │ │ ├── history_view_media.h │ │ │ │ ├── history_view_media_common.cpp │ │ │ │ ├── history_view_media_common.h │ │ │ │ ├── history_view_media_generic.cpp │ │ │ │ ├── history_view_media_generic.h │ │ │ │ ├── history_view_media_grouped.cpp │ │ │ │ ├── history_view_media_grouped.h │ │ │ │ ├── history_view_media_spoiler.cpp │ │ │ │ ├── history_view_media_spoiler.h │ │ │ │ ├── history_view_media_unwrapped.cpp │ │ │ │ ├── history_view_media_unwrapped.h │ │ │ │ ├── history_view_no_forwards_request.cpp │ │ │ │ ├── history_view_no_forwards_request.h │ │ │ │ ├── history_view_photo.cpp │ │ │ │ ├── history_view_photo.h │ │ │ │ ├── history_view_poll.cpp │ │ │ │ ├── history_view_poll.h │ │ │ │ ├── history_view_premium_gift.cpp │ │ │ │ ├── history_view_premium_gift.h │ │ │ │ ├── history_view_save_document_action.cpp │ │ │ │ ├── history_view_save_document_action.h │ │ │ │ ├── history_view_service_box.cpp │ │ │ │ ├── history_view_service_box.h │ │ │ │ ├── history_view_similar_channels.cpp │ │ │ │ ├── history_view_similar_channels.h │ │ │ │ ├── history_view_slot_machine.cpp │ │ │ │ ├── history_view_slot_machine.h │ │ │ │ ├── history_view_sticker.cpp │ │ │ │ ├── history_view_sticker.h │ │ │ │ ├── history_view_sticker_player.cpp │ │ │ │ ├── history_view_sticker_player.h │ │ │ │ ├── history_view_sticker_player_abstract.h │ │ │ │ ├── history_view_story_mention.cpp │ │ │ │ ├── history_view_story_mention.h │ │ │ │ ├── history_view_suggest_decision.cpp │ │ │ │ ├── history_view_suggest_decision.h │ │ │ │ ├── history_view_theme_document.cpp │ │ │ │ ├── history_view_theme_document.h │ │ │ │ ├── history_view_todo_list.cpp │ │ │ │ ├── history_view_todo_list.h │ │ │ │ ├── history_view_unique_gift.cpp │ │ │ │ ├── history_view_unique_gift.h │ │ │ │ ├── history_view_userpic_suggestion.cpp │ │ │ │ ├── history_view_userpic_suggestion.h │ │ │ │ ├── history_view_web_page.cpp │ │ │ │ ├── history_view_web_page.h │ │ │ │ └── menu/ │ │ │ │ ├── history_view_poll_menu.cpp │ │ │ │ └── history_view_poll_menu.h │ │ │ └── reactions/ │ │ │ ├── history_view_reactions.cpp │ │ │ ├── history_view_reactions.h │ │ │ ├── history_view_reactions_button.cpp │ │ │ ├── history_view_reactions_button.h │ │ │ ├── history_view_reactions_list.cpp │ │ │ ├── history_view_reactions_list.h │ │ │ ├── history_view_reactions_selector.cpp │ │ │ ├── history_view_reactions_selector.h │ │ │ ├── history_view_reactions_strip.cpp │ │ │ ├── history_view_reactions_strip.h │ │ │ ├── history_view_reactions_tabs.cpp │ │ │ └── history_view_reactions_tabs.h │ │ ├── info/ │ │ │ ├── bot/ │ │ │ │ ├── earn/ │ │ │ │ │ ├── info_bot_earn_list.cpp │ │ │ │ │ ├── info_bot_earn_list.h │ │ │ │ │ ├── info_bot_earn_widget.cpp │ │ │ │ │ └── info_bot_earn_widget.h │ │ │ │ └── starref/ │ │ │ │ ├── info_bot_starref_common.cpp │ │ │ │ ├── info_bot_starref_common.h │ │ │ │ ├── info_bot_starref_join_widget.cpp │ │ │ │ ├── info_bot_starref_join_widget.h │ │ │ │ ├── info_bot_starref_setup_widget.cpp │ │ │ │ └── info_bot_starref_setup_widget.h │ │ │ ├── channel_statistics/ │ │ │ │ ├── boosts/ │ │ │ │ │ ├── create_giveaway_box.cpp │ │ │ │ │ ├── create_giveaway_box.h │ │ │ │ │ ├── giveaway/ │ │ │ │ │ │ ├── boost_badge.cpp │ │ │ │ │ │ ├── boost_badge.h │ │ │ │ │ │ ├── giveaway.style │ │ │ │ │ │ ├── giveaway_list_controllers.cpp │ │ │ │ │ │ ├── giveaway_list_controllers.h │ │ │ │ │ │ ├── giveaway_type_row.cpp │ │ │ │ │ │ ├── giveaway_type_row.h │ │ │ │ │ │ ├── select_countries_box.cpp │ │ │ │ │ │ └── select_countries_box.h │ │ │ │ │ ├── info_boosts_inner_widget.cpp │ │ │ │ │ ├── info_boosts_inner_widget.h │ │ │ │ │ ├── info_boosts_widget.cpp │ │ │ │ │ └── info_boosts_widget.h │ │ │ │ └── earn/ │ │ │ │ ├── channel_earn.style │ │ │ │ ├── earn_format.cpp │ │ │ │ ├── earn_format.h │ │ │ │ ├── earn_icons.cpp │ │ │ │ ├── earn_icons.h │ │ │ │ ├── info_channel_earn_list.cpp │ │ │ │ ├── info_channel_earn_list.h │ │ │ │ ├── info_channel_earn_widget.cpp │ │ │ │ └── info_channel_earn_widget.h │ │ │ ├── common_groups/ │ │ │ │ ├── info_common_groups_inner_widget.cpp │ │ │ │ ├── info_common_groups_inner_widget.h │ │ │ │ ├── info_common_groups_widget.cpp │ │ │ │ └── info_common_groups_widget.h │ │ │ ├── downloads/ │ │ │ │ ├── info_downloads_inner_widget.cpp │ │ │ │ ├── info_downloads_inner_widget.h │ │ │ │ ├── info_downloads_provider.cpp │ │ │ │ ├── info_downloads_provider.h │ │ │ │ ├── info_downloads_widget.cpp │ │ │ │ └── info_downloads_widget.h │ │ │ ├── global_media/ │ │ │ │ ├── info_global_media_inner_widget.cpp │ │ │ │ ├── info_global_media_inner_widget.h │ │ │ │ ├── info_global_media_provider.cpp │ │ │ │ ├── info_global_media_provider.h │ │ │ │ ├── info_global_media_widget.cpp │ │ │ │ └── info_global_media_widget.h │ │ │ ├── info.style │ │ │ ├── info_content_widget.cpp │ │ │ ├── info_content_widget.h │ │ │ ├── info_controller.cpp │ │ │ ├── info_controller.h │ │ │ ├── info_flexible_scroll.cpp │ │ │ ├── info_flexible_scroll.h │ │ │ ├── info_layer_widget.cpp │ │ │ ├── info_layer_widget.h │ │ │ ├── info_memento.cpp │ │ │ ├── info_memento.h │ │ │ ├── info_section_widget.cpp │ │ │ ├── info_section_widget.h │ │ │ ├── info_top_bar.cpp │ │ │ ├── info_top_bar.h │ │ │ ├── info_wrap_widget.cpp │ │ │ ├── info_wrap_widget.h │ │ │ ├── media/ │ │ │ │ ├── info_media_buttons.cpp │ │ │ │ ├── info_media_buttons.h │ │ │ │ ├── info_media_common.cpp │ │ │ │ ├── info_media_common.h │ │ │ │ ├── info_media_empty_widget.cpp │ │ │ │ ├── info_media_empty_widget.h │ │ │ │ ├── info_media_inner_widget.cpp │ │ │ │ ├── info_media_inner_widget.h │ │ │ │ ├── info_media_list_section.cpp │ │ │ │ ├── info_media_list_section.h │ │ │ │ ├── info_media_list_widget.cpp │ │ │ │ ├── info_media_list_widget.h │ │ │ │ ├── info_media_provider.cpp │ │ │ │ ├── info_media_provider.h │ │ │ │ ├── info_media_widget.cpp │ │ │ │ └── info_media_widget.h │ │ │ ├── members/ │ │ │ │ ├── info_members_widget.cpp │ │ │ │ └── info_members_widget.h │ │ │ ├── peer_gifts/ │ │ │ │ ├── info_peer_gifts_collections.cpp │ │ │ │ ├── info_peer_gifts_collections.h │ │ │ │ ├── info_peer_gifts_common.cpp │ │ │ │ ├── info_peer_gifts_common.h │ │ │ │ ├── info_peer_gifts_widget.cpp │ │ │ │ └── info_peer_gifts_widget.h │ │ │ ├── polls/ │ │ │ │ ├── info_polls_list_widget.cpp │ │ │ │ ├── info_polls_list_widget.h │ │ │ │ ├── info_polls_results_inner_widget.cpp │ │ │ │ ├── info_polls_results_inner_widget.h │ │ │ │ ├── info_polls_results_widget.cpp │ │ │ │ └── info_polls_results_widget.h │ │ │ ├── profile/ │ │ │ │ ├── info_levels.style │ │ │ │ ├── info_profile_actions.cpp │ │ │ │ ├── info_profile_actions.h │ │ │ │ ├── info_profile_badge.cpp │ │ │ │ ├── info_profile_badge.h │ │ │ │ ├── info_profile_badge_tooltip.cpp │ │ │ │ ├── info_profile_badge_tooltip.h │ │ │ │ ├── info_profile_cover.cpp │ │ │ │ ├── info_profile_cover.h │ │ │ │ ├── info_profile_emoji_status_panel.cpp │ │ │ │ ├── info_profile_emoji_status_panel.h │ │ │ │ ├── info_profile_icon.cpp │ │ │ │ ├── info_profile_icon.h │ │ │ │ ├── info_profile_inner_widget.cpp │ │ │ │ ├── info_profile_inner_widget.h │ │ │ │ ├── info_profile_members.cpp │ │ │ │ ├── info_profile_members.h │ │ │ │ ├── info_profile_members_controllers.cpp │ │ │ │ ├── info_profile_members_controllers.h │ │ │ │ ├── info_profile_music_button.cpp │ │ │ │ ├── info_profile_music_button.h │ │ │ │ ├── info_profile_phone_menu.cpp │ │ │ │ ├── info_profile_phone_menu.h │ │ │ │ ├── info_profile_status_label.cpp │ │ │ │ ├── info_profile_status_label.h │ │ │ │ ├── info_profile_text.cpp │ │ │ │ ├── info_profile_text.h │ │ │ │ ├── info_profile_top_bar.cpp │ │ │ │ ├── info_profile_top_bar.h │ │ │ │ ├── info_profile_top_bar_action_button.cpp │ │ │ │ ├── info_profile_top_bar_action_button.h │ │ │ │ ├── info_profile_values.cpp │ │ │ │ ├── info_profile_values.h │ │ │ │ ├── info_profile_widget.cpp │ │ │ │ └── info_profile_widget.h │ │ │ ├── reactions_list/ │ │ │ │ ├── info_reactions_list_widget.cpp │ │ │ │ └── info_reactions_list_widget.h │ │ │ ├── requests_list/ │ │ │ │ ├── info_requests_list_widget.cpp │ │ │ │ └── info_requests_list_widget.h │ │ │ ├── saved/ │ │ │ │ ├── info_saved_music_common.cpp │ │ │ │ ├── info_saved_music_common.h │ │ │ │ ├── info_saved_music_provider.cpp │ │ │ │ ├── info_saved_music_provider.h │ │ │ │ ├── info_saved_music_widget.cpp │ │ │ │ ├── info_saved_music_widget.h │ │ │ │ ├── info_saved_sublists_widget.cpp │ │ │ │ └── info_saved_sublists_widget.h │ │ │ ├── settings/ │ │ │ │ ├── info_settings_widget.cpp │ │ │ │ └── info_settings_widget.h │ │ │ ├── similar_peers/ │ │ │ │ ├── info_similar_peers_widget.cpp │ │ │ │ └── info_similar_peers_widget.h │ │ │ ├── statistics/ │ │ │ │ ├── info_statistics_common.h │ │ │ │ ├── info_statistics_inner_widget.cpp │ │ │ │ ├── info_statistics_inner_widget.h │ │ │ │ ├── info_statistics_list_controllers.cpp │ │ │ │ ├── info_statistics_list_controllers.h │ │ │ │ ├── info_statistics_recent_message.cpp │ │ │ │ ├── info_statistics_recent_message.h │ │ │ │ ├── info_statistics_tag.h │ │ │ │ ├── info_statistics_widget.cpp │ │ │ │ └── info_statistics_widget.h │ │ │ ├── stories/ │ │ │ │ ├── info_stories_albums.cpp │ │ │ │ ├── info_stories_albums.h │ │ │ │ ├── info_stories_common.h │ │ │ │ ├── info_stories_inner_widget.cpp │ │ │ │ ├── info_stories_inner_widget.h │ │ │ │ ├── info_stories_provider.cpp │ │ │ │ ├── info_stories_provider.h │ │ │ │ ├── info_stories_widget.cpp │ │ │ │ └── info_stories_widget.h │ │ │ └── userpic/ │ │ │ ├── info_userpic_bubble_wrap.cpp │ │ │ ├── info_userpic_bubble_wrap.h │ │ │ ├── info_userpic_builder.style │ │ │ ├── info_userpic_color_circle_button.cpp │ │ │ ├── info_userpic_color_circle_button.h │ │ │ ├── info_userpic_colors_editor.cpp │ │ │ ├── info_userpic_colors_editor.h │ │ │ ├── info_userpic_emoji_builder.cpp │ │ │ ├── info_userpic_emoji_builder.h │ │ │ ├── info_userpic_emoji_builder_common.cpp │ │ │ ├── info_userpic_emoji_builder_common.h │ │ │ ├── info_userpic_emoji_builder_layer.cpp │ │ │ ├── info_userpic_emoji_builder_layer.h │ │ │ ├── info_userpic_emoji_builder_menu_item.cpp │ │ │ ├── info_userpic_emoji_builder_menu_item.h │ │ │ ├── info_userpic_emoji_builder_preview.cpp │ │ │ ├── info_userpic_emoji_builder_preview.h │ │ │ ├── info_userpic_emoji_builder_widget.cpp │ │ │ └── info_userpic_emoji_builder_widget.h │ │ ├── inline_bots/ │ │ │ ├── bot_attach_web_view.cpp │ │ │ ├── bot_attach_web_view.h │ │ │ ├── inline_bot_confirm_prepared.cpp │ │ │ ├── inline_bot_confirm_prepared.h │ │ │ ├── inline_bot_downloads.cpp │ │ │ ├── inline_bot_downloads.h │ │ │ ├── inline_bot_layout_internal.cpp │ │ │ ├── inline_bot_layout_internal.h │ │ │ ├── inline_bot_layout_item.cpp │ │ │ ├── inline_bot_layout_item.h │ │ │ ├── inline_bot_result.cpp │ │ │ ├── inline_bot_result.h │ │ │ ├── inline_bot_send_data.cpp │ │ │ ├── inline_bot_send_data.h │ │ │ ├── inline_bot_storage.cpp │ │ │ ├── inline_bot_storage.h │ │ │ ├── inline_results_inner.cpp │ │ │ ├── inline_results_inner.h │ │ │ ├── inline_results_widget.cpp │ │ │ └── inline_results_widget.h │ │ ├── intro/ │ │ │ ├── intro.style │ │ │ ├── intro_code.cpp │ │ │ ├── intro_code.h │ │ │ ├── intro_code_input.cpp │ │ │ ├── intro_code_input.h │ │ │ ├── intro_email.cpp │ │ │ ├── intro_email.h │ │ │ ├── intro_password_check.cpp │ │ │ ├── intro_password_check.h │ │ │ ├── intro_phone.cpp │ │ │ ├── intro_phone.h │ │ │ ├── intro_qr.cpp │ │ │ ├── intro_qr.h │ │ │ ├── intro_signup.cpp │ │ │ ├── intro_signup.h │ │ │ ├── intro_start.cpp │ │ │ ├── intro_start.h │ │ │ ├── intro_step.cpp │ │ │ ├── intro_step.h │ │ │ ├── intro_widget.cpp │ │ │ └── intro_widget.h │ │ ├── iv/ │ │ │ ├── iv.style │ │ │ ├── iv_controller.cpp │ │ │ ├── iv_controller.h │ │ │ ├── iv_data.cpp │ │ │ ├── iv_data.h │ │ │ ├── iv_delegate.h │ │ │ ├── iv_delegate_impl.cpp │ │ │ ├── iv_delegate_impl.h │ │ │ ├── iv_instance.cpp │ │ │ ├── iv_instance.h │ │ │ ├── iv_pch.h │ │ │ ├── iv_prepare.cpp │ │ │ └── iv_prepare.h │ │ ├── lang/ │ │ │ ├── lang_cloud_manager.cpp │ │ │ ├── lang_cloud_manager.h │ │ │ ├── lang_file_parser.cpp │ │ │ ├── lang_file_parser.h │ │ │ ├── lang_hardcoded.h │ │ │ ├── lang_instance.cpp │ │ │ ├── lang_instance.h │ │ │ ├── lang_keys.cpp │ │ │ ├── lang_keys.h │ │ │ ├── lang_numbers_animation.cpp │ │ │ ├── lang_numbers_animation.h │ │ │ ├── lang_pch.h │ │ │ ├── lang_tag.cpp │ │ │ ├── lang_tag.h │ │ │ ├── lang_text_entity.cpp │ │ │ ├── lang_text_entity.h │ │ │ ├── lang_translator.cpp │ │ │ ├── lang_translator.h │ │ │ ├── lang_values.h │ │ │ ├── translate_mtproto_provider.cpp │ │ │ ├── translate_mtproto_provider.h │ │ │ ├── translate_provider.cpp │ │ │ ├── translate_provider.h │ │ │ ├── translate_url_provider.cpp │ │ │ └── translate_url_provider.h │ │ ├── languages.h │ │ ├── layout/ │ │ │ ├── abstract_layout_item.cpp │ │ │ ├── abstract_layout_item.h │ │ │ ├── layout_document_generic_preview.cpp │ │ │ ├── layout_document_generic_preview.h │ │ │ ├── layout_item_base.cpp │ │ │ ├── layout_item_base.h │ │ │ ├── layout_mosaic.cpp │ │ │ ├── layout_mosaic.h │ │ │ ├── layout_position.cpp │ │ │ ├── layout_position.h │ │ │ ├── layout_selection.cpp │ │ │ └── layout_selection.h │ │ ├── logs.cpp │ │ ├── logs.h │ │ ├── main/ │ │ │ ├── main_account.cpp │ │ │ ├── main_account.h │ │ │ ├── main_app_config.cpp │ │ │ ├── main_app_config.h │ │ │ ├── main_app_config_values.cpp │ │ │ ├── main_app_config_values.h │ │ │ ├── main_domain.cpp │ │ │ ├── main_domain.h │ │ │ ├── main_session.cpp │ │ │ ├── main_session.h │ │ │ ├── main_session_settings.cpp │ │ │ ├── main_session_settings.h │ │ │ └── session/ │ │ │ ├── send_as_peers.cpp │ │ │ ├── send_as_peers.h │ │ │ ├── session_show.cpp │ │ │ └── session_show.h │ │ ├── main.cpp │ │ ├── mainwidget.cpp │ │ ├── mainwidget.h │ │ ├── mainwindow.cpp │ │ ├── mainwindow.h │ │ ├── media/ │ │ │ ├── audio/ │ │ │ │ ├── media_audio.cpp │ │ │ │ ├── media_audio.h │ │ │ │ ├── media_audio_capture.cpp │ │ │ │ ├── media_audio_capture.h │ │ │ │ ├── media_audio_capture_common.h │ │ │ │ ├── media_audio_edit.cpp │ │ │ │ ├── media_audio_edit.h │ │ │ │ ├── media_audio_ffmpeg_loader.cpp │ │ │ │ ├── media_audio_ffmpeg_loader.h │ │ │ │ ├── media_audio_loader.cpp │ │ │ │ ├── media_audio_loader.h │ │ │ │ ├── media_audio_loaders.cpp │ │ │ │ ├── media_audio_loaders.h │ │ │ │ ├── media_audio_local_cache.cpp │ │ │ │ ├── media_audio_local_cache.h │ │ │ │ ├── media_audio_track.cpp │ │ │ │ ├── media_audio_track.h │ │ │ │ ├── media_child_ffmpeg_loader.cpp │ │ │ │ └── media_child_ffmpeg_loader.h │ │ │ ├── clip/ │ │ │ │ ├── media_clip_check_streaming.cpp │ │ │ │ ├── media_clip_check_streaming.h │ │ │ │ ├── media_clip_ffmpeg.cpp │ │ │ │ ├── media_clip_ffmpeg.h │ │ │ │ ├── media_clip_implementation.cpp │ │ │ │ ├── media_clip_implementation.h │ │ │ │ ├── media_clip_reader.cpp │ │ │ │ └── media_clip_reader.h │ │ │ ├── media_common.h │ │ │ ├── player/ │ │ │ │ ├── media_player.style │ │ │ │ ├── media_player_button.cpp │ │ │ │ ├── media_player_button.h │ │ │ │ ├── media_player_dropdown.cpp │ │ │ │ ├── media_player_dropdown.h │ │ │ │ ├── media_player_float.cpp │ │ │ │ ├── media_player_float.h │ │ │ │ ├── media_player_instance.cpp │ │ │ │ ├── media_player_instance.h │ │ │ │ ├── media_player_listen_tracker.cpp │ │ │ │ ├── media_player_listen_tracker.h │ │ │ │ ├── media_player_panel.cpp │ │ │ │ ├── media_player_panel.h │ │ │ │ ├── media_player_volume_controller.cpp │ │ │ │ ├── media_player_volume_controller.h │ │ │ │ ├── media_player_widget.cpp │ │ │ │ └── media_player_widget.h │ │ │ ├── stories/ │ │ │ │ ├── media_stories.style │ │ │ │ ├── media_stories_caption_full_view.cpp │ │ │ │ ├── media_stories_caption_full_view.h │ │ │ │ ├── media_stories_controller.cpp │ │ │ │ ├── media_stories_controller.h │ │ │ │ ├── media_stories_delegate.cpp │ │ │ │ ├── media_stories_delegate.h │ │ │ │ ├── media_stories_header.cpp │ │ │ │ ├── media_stories_header.h │ │ │ │ ├── media_stories_reactions.cpp │ │ │ │ ├── media_stories_reactions.h │ │ │ │ ├── media_stories_recent_views.cpp │ │ │ │ ├── media_stories_recent_views.h │ │ │ │ ├── media_stories_reply.cpp │ │ │ │ ├── media_stories_reply.h │ │ │ │ ├── media_stories_repost_view.cpp │ │ │ │ ├── media_stories_repost_view.h │ │ │ │ ├── media_stories_share.cpp │ │ │ │ ├── media_stories_share.h │ │ │ │ ├── media_stories_sibling.cpp │ │ │ │ ├── media_stories_sibling.h │ │ │ │ ├── media_stories_slider.cpp │ │ │ │ ├── media_stories_slider.h │ │ │ │ ├── media_stories_stealth.cpp │ │ │ │ ├── media_stories_stealth.h │ │ │ │ ├── media_stories_view.cpp │ │ │ │ └── media_stories_view.h │ │ │ ├── streaming/ │ │ │ │ ├── media_streaming_audio_track.cpp │ │ │ │ ├── media_streaming_audio_track.h │ │ │ │ ├── media_streaming_common.h │ │ │ │ ├── media_streaming_document.cpp │ │ │ │ ├── media_streaming_document.h │ │ │ │ ├── media_streaming_file.cpp │ │ │ │ ├── media_streaming_file.h │ │ │ │ ├── media_streaming_file_delegate.h │ │ │ │ ├── media_streaming_instance.cpp │ │ │ │ ├── media_streaming_instance.h │ │ │ │ ├── media_streaming_loader.cpp │ │ │ │ ├── media_streaming_loader.h │ │ │ │ ├── media_streaming_loader_local.cpp │ │ │ │ ├── media_streaming_loader_local.h │ │ │ │ ├── media_streaming_loader_mtproto.cpp │ │ │ │ ├── media_streaming_loader_mtproto.h │ │ │ │ ├── media_streaming_player.cpp │ │ │ │ ├── media_streaming_player.h │ │ │ │ ├── media_streaming_reader.cpp │ │ │ │ ├── media_streaming_reader.h │ │ │ │ ├── media_streaming_round_preview.cpp │ │ │ │ ├── media_streaming_round_preview.h │ │ │ │ ├── media_streaming_utility.cpp │ │ │ │ ├── media_streaming_utility.h │ │ │ │ ├── media_streaming_video_track.cpp │ │ │ │ └── media_streaming_video_track.h │ │ │ ├── system_media_controls_manager.cpp │ │ │ ├── system_media_controls_manager.h │ │ │ └── view/ │ │ │ ├── media_view.style │ │ │ ├── media_view_group_thumbs.cpp │ │ │ ├── media_view_group_thumbs.h │ │ │ ├── media_view_metal_texture.h │ │ │ ├── media_view_metal_texture.mm │ │ │ ├── media_view_open_common.cpp │ │ │ ├── media_view_open_common.h │ │ │ ├── media_view_overlay_opengl.cpp │ │ │ ├── media_view_overlay_opengl.h │ │ │ ├── media_view_overlay_raster.cpp │ │ │ ├── media_view_overlay_raster.h │ │ │ ├── media_view_overlay_renderer.h │ │ │ ├── media_view_overlay_rhi.cpp │ │ │ ├── media_view_overlay_rhi.h │ │ │ ├── media_view_overlay_widget.cpp │ │ │ ├── media_view_overlay_widget.h │ │ │ ├── media_view_pip.cpp │ │ │ ├── media_view_pip.h │ │ │ ├── media_view_pip_opengl.cpp │ │ │ ├── media_view_pip_opengl.h │ │ │ ├── media_view_pip_raster.cpp │ │ │ ├── media_view_pip_raster.h │ │ │ ├── media_view_pip_renderer.h │ │ │ ├── media_view_pip_rhi.cpp │ │ │ ├── media_view_pip_rhi.h │ │ │ ├── media_view_playback_controls.cpp │ │ │ ├── media_view_playback_controls.h │ │ │ ├── media_view_playback_progress.cpp │ │ │ ├── media_view_playback_progress.h │ │ │ ├── media_view_playback_sponsored.cpp │ │ │ ├── media_view_playback_sponsored.h │ │ │ ├── media_view_video_stream.cpp │ │ │ └── media_view_video_stream.h │ │ ├── menu/ │ │ │ ├── gift_resale_filter.cpp │ │ │ ├── gift_resale_filter.h │ │ │ ├── menu_antispam_validator.cpp │ │ │ ├── menu_antispam_validator.h │ │ │ ├── menu_check_item.cpp │ │ │ ├── menu_check_item.h │ │ │ ├── menu_checked_action.cpp │ │ │ ├── menu_checked_action.h │ │ │ ├── menu_dock.cpp │ │ │ ├── menu_dock.h │ │ │ ├── menu_item_download_files.cpp │ │ │ ├── menu_item_download_files.h │ │ │ ├── menu_item_rate_transcribe.cpp │ │ │ ├── menu_item_rate_transcribe.h │ │ │ ├── menu_item_rate_transcribe_session.cpp │ │ │ ├── menu_item_rate_transcribe_session.h │ │ │ ├── menu_mute.cpp │ │ │ ├── menu_mute.h │ │ │ ├── menu_send.cpp │ │ │ ├── menu_send.h │ │ │ ├── menu_sponsored.cpp │ │ │ ├── menu_sponsored.h │ │ │ ├── menu_timecode_action.cpp │ │ │ ├── menu_timecode_action.h │ │ │ ├── menu_ttl.cpp │ │ │ ├── menu_ttl.h │ │ │ ├── menu_ttl_validator.cpp │ │ │ └── menu_ttl_validator.h │ │ ├── mtproto/ │ │ │ ├── config_loader.cpp │ │ │ ├── config_loader.h │ │ │ ├── connection_abstract.cpp │ │ │ ├── connection_abstract.h │ │ │ ├── connection_http.cpp │ │ │ ├── connection_http.h │ │ │ ├── connection_resolving.cpp │ │ │ ├── connection_resolving.h │ │ │ ├── connection_tcp.cpp │ │ │ ├── connection_tcp.h │ │ │ ├── core_types.h │ │ │ ├── dedicated_file_loader.cpp │ │ │ ├── dedicated_file_loader.h │ │ │ ├── details/ │ │ │ │ ├── mtproto_abstract_socket.cpp │ │ │ │ ├── mtproto_abstract_socket.h │ │ │ │ ├── mtproto_bound_key_creator.cpp │ │ │ │ ├── mtproto_bound_key_creator.h │ │ │ │ ├── mtproto_dc_key_binder.cpp │ │ │ │ ├── mtproto_dc_key_binder.h │ │ │ │ ├── mtproto_dc_key_creator.cpp │ │ │ │ ├── mtproto_dc_key_creator.h │ │ │ │ ├── mtproto_dcenter.cpp │ │ │ │ ├── mtproto_dcenter.h │ │ │ │ ├── mtproto_domain_resolver.cpp │ │ │ │ ├── mtproto_domain_resolver.h │ │ │ │ ├── mtproto_dump_to_text.cpp │ │ │ │ ├── mtproto_dump_to_text.h │ │ │ │ ├── mtproto_received_ids_manager.cpp │ │ │ │ ├── mtproto_received_ids_manager.h │ │ │ │ ├── mtproto_rsa_public_key.cpp │ │ │ │ ├── mtproto_rsa_public_key.h │ │ │ │ ├── mtproto_serialized_request.cpp │ │ │ │ ├── mtproto_serialized_request.h │ │ │ │ ├── mtproto_tcp_socket.cpp │ │ │ │ ├── mtproto_tcp_socket.h │ │ │ │ ├── mtproto_tls_socket.cpp │ │ │ │ └── mtproto_tls_socket.h │ │ │ ├── facade.cpp │ │ │ ├── facade.h │ │ │ ├── mtp_instance.cpp │ │ │ ├── mtp_instance.h │ │ │ ├── mtproto_auth_key.cpp │ │ │ ├── mtproto_auth_key.h │ │ │ ├── mtproto_concurrent_sender.cpp │ │ │ ├── mtproto_concurrent_sender.h │ │ │ ├── mtproto_config.cpp │ │ │ ├── mtproto_config.h │ │ │ ├── mtproto_dc_options.cpp │ │ │ ├── mtproto_dc_options.h │ │ │ ├── mtproto_dh_utils.cpp │ │ │ ├── mtproto_dh_utils.h │ │ │ ├── mtproto_pch.h │ │ │ ├── mtproto_proxy_data.cpp │ │ │ ├── mtproto_proxy_data.h │ │ │ ├── mtproto_response.cpp │ │ │ ├── mtproto_response.h │ │ │ ├── scheme/ │ │ │ │ ├── api.tl │ │ │ │ └── mtproto.tl │ │ │ ├── sender.h │ │ │ ├── session.cpp │ │ │ ├── session.h │ │ │ ├── session_private.cpp │ │ │ ├── session_private.h │ │ │ ├── special_config_request.cpp │ │ │ ├── special_config_request.h │ │ │ └── type_utils.h │ │ ├── old_settings/ │ │ │ ├── settings_chat_settings_widget.cpp │ │ │ └── settings_chat_settings_widget.h │ │ ├── overview/ │ │ │ ├── overview.style │ │ │ ├── overview_checkbox.cpp │ │ │ ├── overview_checkbox.h │ │ │ ├── overview_layout.cpp │ │ │ ├── overview_layout.h │ │ │ └── overview_layout_delegate.h │ │ ├── passport/ │ │ │ ├── passport.style │ │ │ ├── passport_edit_identity_box.cpp │ │ │ ├── passport_edit_identity_box.h │ │ │ ├── passport_encryption.cpp │ │ │ ├── passport_encryption.h │ │ │ ├── passport_form_controller.cpp │ │ │ ├── passport_form_controller.h │ │ │ ├── passport_form_row.cpp │ │ │ ├── passport_form_row.h │ │ │ ├── passport_form_view_controller.cpp │ │ │ ├── passport_form_view_controller.h │ │ │ ├── passport_panel.cpp │ │ │ ├── passport_panel.h │ │ │ ├── passport_panel_controller.cpp │ │ │ ├── passport_panel_controller.h │ │ │ ├── passport_panel_edit_contact.cpp │ │ │ ├── passport_panel_edit_contact.h │ │ │ ├── passport_panel_edit_document.cpp │ │ │ ├── passport_panel_edit_document.h │ │ │ ├── passport_panel_edit_scans.cpp │ │ │ ├── passport_panel_edit_scans.h │ │ │ ├── passport_panel_form.cpp │ │ │ ├── passport_panel_form.h │ │ │ ├── passport_panel_password.cpp │ │ │ ├── passport_panel_password.h │ │ │ └── ui/ │ │ │ ├── passport_details_row.cpp │ │ │ ├── passport_details_row.h │ │ │ ├── passport_form_row.cpp │ │ │ └── passport_form_row.h │ │ ├── payments/ │ │ │ ├── payments_checkout_process.cpp │ │ │ ├── payments_checkout_process.h │ │ │ ├── payments_form.cpp │ │ │ ├── payments_form.h │ │ │ ├── payments_non_panel_process.cpp │ │ │ ├── payments_non_panel_process.h │ │ │ ├── payments_reaction_process.cpp │ │ │ ├── payments_reaction_process.h │ │ │ ├── smartglocal/ │ │ │ │ ├── smartglocal_api_client.cpp │ │ │ │ ├── smartglocal_api_client.h │ │ │ │ ├── smartglocal_callbacks.h │ │ │ │ ├── smartglocal_card.cpp │ │ │ │ ├── smartglocal_card.h │ │ │ │ ├── smartglocal_error.cpp │ │ │ │ ├── smartglocal_error.h │ │ │ │ ├── smartglocal_token.cpp │ │ │ │ └── smartglocal_token.h │ │ │ ├── stripe/ │ │ │ │ ├── stripe_address.h │ │ │ │ ├── stripe_api_client.cpp │ │ │ │ ├── stripe_api_client.h │ │ │ │ ├── stripe_callbacks.h │ │ │ │ ├── stripe_card.cpp │ │ │ │ ├── stripe_card.h │ │ │ │ ├── stripe_card_params.cpp │ │ │ │ ├── stripe_card_params.h │ │ │ │ ├── stripe_card_validator.cpp │ │ │ │ ├── stripe_card_validator.h │ │ │ │ ├── stripe_decode.cpp │ │ │ │ ├── stripe_decode.h │ │ │ │ ├── stripe_error.cpp │ │ │ │ ├── stripe_error.h │ │ │ │ ├── stripe_form_encodable.h │ │ │ │ ├── stripe_form_encoder.cpp │ │ │ │ ├── stripe_form_encoder.h │ │ │ │ ├── stripe_payment_configuration.h │ │ │ │ ├── stripe_pch.h │ │ │ │ ├── stripe_token.cpp │ │ │ │ └── stripe_token.h │ │ │ └── ui/ │ │ │ ├── payments.style │ │ │ ├── payments_edit_card.cpp │ │ │ ├── payments_edit_card.h │ │ │ ├── payments_edit_information.cpp │ │ │ ├── payments_edit_information.h │ │ │ ├── payments_field.cpp │ │ │ ├── payments_field.h │ │ │ ├── payments_form_summary.cpp │ │ │ ├── payments_form_summary.h │ │ │ ├── payments_panel.cpp │ │ │ ├── payments_panel.h │ │ │ ├── payments_panel_data.h │ │ │ ├── payments_panel_delegate.h │ │ │ ├── payments_reaction_box.cpp │ │ │ └── payments_reaction_box.h │ │ ├── platform/ │ │ │ ├── linux/ │ │ │ │ ├── current_geo_location_linux.cpp │ │ │ │ ├── current_geo_location_linux.h │ │ │ │ ├── file_utilities_linux.cpp │ │ │ │ ├── file_utilities_linux.h │ │ │ │ ├── integration_linux.cpp │ │ │ │ ├── integration_linux.h │ │ │ │ ├── launcher_linux.cpp │ │ │ │ ├── launcher_linux.h │ │ │ │ ├── main_window_linux.cpp │ │ │ │ ├── main_window_linux.h │ │ │ │ ├── notifications_manager_linux.cpp │ │ │ │ ├── notifications_manager_linux.h │ │ │ │ ├── org.freedesktop.Notifications.xml │ │ │ │ ├── overlay_widget_linux.h │ │ │ │ ├── specific_linux.cpp │ │ │ │ ├── specific_linux.h │ │ │ │ ├── text_recognition_linux.h │ │ │ │ ├── translate_provider_linux.cpp │ │ │ │ ├── translate_provider_linux.h │ │ │ │ ├── tray_linux.cpp │ │ │ │ ├── tray_linux.h │ │ │ │ └── webauthn_linux.cpp │ │ │ ├── mac/ │ │ │ │ ├── current_geo_location_mac.h │ │ │ │ ├── current_geo_location_mac.mm │ │ │ │ ├── file_bookmark_mac.h │ │ │ │ ├── file_bookmark_mac.mm │ │ │ │ ├── file_utilities_mac.h │ │ │ │ ├── file_utilities_mac.mm │ │ │ │ ├── integration_mac.h │ │ │ │ ├── integration_mac.mm │ │ │ │ ├── launcher_mac.h │ │ │ │ ├── launcher_mac.mm │ │ │ │ ├── mac_iconv_helper.c │ │ │ │ ├── main_window_mac.h │ │ │ │ ├── main_window_mac.mm │ │ │ │ ├── notifications_manager_mac.h │ │ │ │ ├── notifications_manager_mac.mm │ │ │ │ ├── overlay_widget_mac.h │ │ │ │ ├── overlay_widget_mac.mm │ │ │ │ ├── specific_mac.h │ │ │ │ ├── specific_mac.mm │ │ │ │ ├── specific_mac_p.h │ │ │ │ ├── specific_mac_p.mm │ │ │ │ ├── text_recognition_mac.h │ │ │ │ ├── text_recognition_mac.mm │ │ │ │ ├── touchbar/ │ │ │ │ │ ├── items/ │ │ │ │ │ │ ├── mac_formatter_item.h │ │ │ │ │ │ ├── mac_formatter_item.mm │ │ │ │ │ │ ├── mac_pinned_chats_item.h │ │ │ │ │ │ ├── mac_pinned_chats_item.mm │ │ │ │ │ │ ├── mac_scrubber_item.h │ │ │ │ │ │ └── mac_scrubber_item.mm │ │ │ │ │ ├── mac_touchbar_audio.h │ │ │ │ │ ├── mac_touchbar_audio.mm │ │ │ │ │ ├── mac_touchbar_common.h │ │ │ │ │ ├── mac_touchbar_common.mm │ │ │ │ │ ├── mac_touchbar_controls.h │ │ │ │ │ ├── mac_touchbar_controls.mm │ │ │ │ │ ├── mac_touchbar_main.h │ │ │ │ │ ├── mac_touchbar_main.mm │ │ │ │ │ ├── mac_touchbar_manager.h │ │ │ │ │ ├── mac_touchbar_manager.mm │ │ │ │ │ ├── mac_touchbar_media_view.h │ │ │ │ │ └── mac_touchbar_media_view.mm │ │ │ │ ├── translate_provider_mac.h │ │ │ │ ├── translate_provider_mac.mm │ │ │ │ ├── tray_mac.h │ │ │ │ ├── tray_mac.mm │ │ │ │ ├── webauthn_mac.mm │ │ │ │ └── window_title_mac.mm │ │ │ ├── platform_current_geo_location.h │ │ │ ├── platform_file_bookmark.h │ │ │ ├── platform_file_utilities.h │ │ │ ├── platform_integration.cpp │ │ │ ├── platform_integration.h │ │ │ ├── platform_launcher.h │ │ │ ├── platform_main_window.h │ │ │ ├── platform_notifications_manager.h │ │ │ ├── platform_overlay_widget.cpp │ │ │ ├── platform_overlay_widget.h │ │ │ ├── platform_specific.h │ │ │ ├── platform_text_recognition.h │ │ │ ├── platform_translate_provider.h │ │ │ ├── platform_tray.h │ │ │ ├── platform_webauthn.h │ │ │ ├── platform_window_title.h │ │ │ └── win/ │ │ │ ├── current_geo_location_win.cpp │ │ │ ├── current_geo_location_win.h │ │ │ ├── file_utilities_win.cpp │ │ │ ├── file_utilities_win.h │ │ │ ├── integration_win.cpp │ │ │ ├── integration_win.h │ │ │ ├── launcher_win.cpp │ │ │ ├── launcher_win.h │ │ │ ├── main_window_win.cpp │ │ │ ├── main_window_win.h │ │ │ ├── notifications_manager_win.cpp │ │ │ ├── notifications_manager_win.h │ │ │ ├── overlay_widget_win.h │ │ │ ├── specific_win.cpp │ │ │ ├── specific_win.h │ │ │ ├── text_recognition_win.h │ │ │ ├── translate_provider_win.h │ │ │ ├── tray_win.cpp │ │ │ ├── tray_win.h │ │ │ ├── webauthn_win.cpp │ │ │ ├── windows_app_user_model_id.cpp │ │ │ ├── windows_app_user_model_id.h │ │ │ ├── windows_autostart_task.cpp │ │ │ ├── windows_autostart_task.h │ │ │ ├── windows_dlls.cpp │ │ │ ├── windows_dlls.h │ │ │ ├── windows_quiethours.idl │ │ │ ├── windows_toast_activator.cpp │ │ │ ├── windows_toast_activator.h │ │ │ └── windows_toastactivator.idl │ │ ├── poll/ │ │ │ ├── poll_media_upload.cpp │ │ │ └── poll_media_upload.h │ │ ├── profile/ │ │ │ ├── profile.style │ │ │ ├── profile_back_button.cpp │ │ │ ├── profile_back_button.h │ │ │ ├── profile_block_widget.cpp │ │ │ ├── profile_block_widget.h │ │ │ ├── profile_cover_drop_area.cpp │ │ │ └── profile_cover_drop_area.h │ │ ├── settings/ │ │ │ ├── business/ │ │ │ │ ├── settings_away_message.cpp │ │ │ │ ├── settings_away_message.h │ │ │ │ ├── settings_chat_intro.cpp │ │ │ │ ├── settings_chat_intro.h │ │ │ │ ├── settings_chat_links.cpp │ │ │ │ ├── settings_chat_links.h │ │ │ │ ├── settings_chatbots.cpp │ │ │ │ ├── settings_chatbots.h │ │ │ │ ├── settings_greeting.cpp │ │ │ │ ├── settings_greeting.h │ │ │ │ ├── settings_location.cpp │ │ │ │ ├── settings_location.h │ │ │ │ ├── settings_quick_replies.cpp │ │ │ │ ├── settings_quick_replies.h │ │ │ │ ├── settings_recipients_helper.cpp │ │ │ │ ├── settings_recipients_helper.h │ │ │ │ ├── settings_shortcut_messages.cpp │ │ │ │ ├── settings_shortcut_messages.h │ │ │ │ ├── settings_working_hours.cpp │ │ │ │ └── settings_working_hours.h │ │ │ ├── cloud_password/ │ │ │ │ ├── settings_cloud_password_common.cpp │ │ │ │ ├── settings_cloud_password_common.h │ │ │ │ ├── settings_cloud_password_email.cpp │ │ │ │ ├── settings_cloud_password_email.h │ │ │ │ ├── settings_cloud_password_email_confirm.cpp │ │ │ │ ├── settings_cloud_password_email_confirm.h │ │ │ │ ├── settings_cloud_password_hint.cpp │ │ │ │ ├── settings_cloud_password_hint.h │ │ │ │ ├── settings_cloud_password_input.cpp │ │ │ │ ├── settings_cloud_password_input.h │ │ │ │ ├── settings_cloud_password_login_email.cpp │ │ │ │ ├── settings_cloud_password_login_email.h │ │ │ │ ├── settings_cloud_password_login_email_confirm.cpp │ │ │ │ ├── settings_cloud_password_login_email_confirm.h │ │ │ │ ├── settings_cloud_password_manage.cpp │ │ │ │ ├── settings_cloud_password_manage.h │ │ │ │ ├── settings_cloud_password_start.cpp │ │ │ │ ├── settings_cloud_password_start.h │ │ │ │ ├── settings_cloud_password_step.cpp │ │ │ │ ├── settings_cloud_password_step.h │ │ │ │ ├── settings_cloud_password_validate_icon.cpp │ │ │ │ └── settings_cloud_password_validate_icon.h │ │ │ ├── detailed_settings_button.cpp │ │ │ ├── detailed_settings_button.h │ │ │ ├── sections/ │ │ │ │ ├── settings_active_sessions.cpp │ │ │ │ ├── settings_active_sessions.h │ │ │ │ ├── settings_advanced.cpp │ │ │ │ ├── settings_advanced.h │ │ │ │ ├── settings_blocked_peers.cpp │ │ │ │ ├── settings_blocked_peers.h │ │ │ │ ├── settings_business.cpp │ │ │ │ ├── settings_business.h │ │ │ │ ├── settings_calls.cpp │ │ │ │ ├── settings_calls.h │ │ │ │ ├── settings_chat.cpp │ │ │ │ ├── settings_chat.h │ │ │ │ ├── settings_credits.cpp │ │ │ │ ├── settings_credits.h │ │ │ │ ├── settings_folders.cpp │ │ │ │ ├── settings_folders.h │ │ │ │ ├── settings_fork.cpp │ │ │ │ ├── settings_fork.h │ │ │ │ ├── settings_global_ttl.cpp │ │ │ │ ├── settings_global_ttl.h │ │ │ │ ├── settings_information.cpp │ │ │ │ ├── settings_information.h │ │ │ │ ├── settings_link_device.cpp │ │ │ │ ├── settings_link_device.h │ │ │ │ ├── settings_local_passcode.cpp │ │ │ │ ├── settings_local_passcode.h │ │ │ │ ├── settings_main.cpp │ │ │ │ ├── settings_main.h │ │ │ │ ├── settings_notifications.cpp │ │ │ │ ├── settings_notifications.h │ │ │ │ ├── settings_notifications_reactions.cpp │ │ │ │ ├── settings_notifications_reactions.h │ │ │ │ ├── settings_notifications_type.cpp │ │ │ │ ├── settings_notifications_type.h │ │ │ │ ├── settings_passkeys.cpp │ │ │ │ ├── settings_passkeys.h │ │ │ │ ├── settings_premium.cpp │ │ │ │ ├── settings_premium.h │ │ │ │ ├── settings_privacy_security.cpp │ │ │ │ ├── settings_privacy_security.h │ │ │ │ ├── settings_shortcuts.cpp │ │ │ │ ├── settings_shortcuts.h │ │ │ │ ├── settings_websites.cpp │ │ │ │ └── settings_websites.h │ │ │ ├── settings.style │ │ │ ├── settings_builder.cpp │ │ │ ├── settings_builder.h │ │ │ ├── settings_codes.cpp │ │ │ ├── settings_codes.h │ │ │ ├── settings_common.cpp │ │ │ ├── settings_common.h │ │ │ ├── settings_common_session.cpp │ │ │ ├── settings_common_session.h │ │ │ ├── settings_credits_graphics.cpp │ │ │ ├── settings_credits_graphics.h │ │ │ ├── settings_experimental.cpp │ │ │ ├── settings_experimental.h │ │ │ ├── settings_faq_suggestions.cpp │ │ │ ├── settings_faq_suggestions.h │ │ │ ├── settings_intro.cpp │ │ │ ├── settings_intro.h │ │ │ ├── settings_notifications_common.h │ │ │ ├── settings_power_saving.cpp │ │ │ ├── settings_power_saving.h │ │ │ ├── settings_privacy_controllers.cpp │ │ │ ├── settings_privacy_controllers.h │ │ │ ├── settings_recent_searches.cpp │ │ │ ├── settings_recent_searches.h │ │ │ ├── settings_scale_preview.cpp │ │ │ ├── settings_scale_preview.h │ │ │ ├── settings_search.cpp │ │ │ ├── settings_search.h │ │ │ └── settings_type.h │ │ ├── settings.cpp │ │ ├── settings.h │ │ ├── statistics/ │ │ │ ├── chart_lines_filter_controller.cpp │ │ │ ├── chart_lines_filter_controller.h │ │ │ ├── chart_rulers_data.cpp │ │ │ ├── chart_rulers_data.h │ │ │ ├── chart_widget.cpp │ │ │ ├── chart_widget.h │ │ │ ├── segment_tree.cpp │ │ │ ├── segment_tree.h │ │ │ ├── statistics.style │ │ │ ├── statistics_common.h │ │ │ ├── statistics_data_deserialize.cpp │ │ │ ├── statistics_data_deserialize.h │ │ │ ├── statistics_format_values.cpp │ │ │ ├── statistics_format_values.h │ │ │ ├── statistics_graphics.cpp │ │ │ ├── statistics_graphics.h │ │ │ ├── statistics_types.h │ │ │ ├── view/ │ │ │ │ ├── abstract_chart_view.cpp │ │ │ │ ├── abstract_chart_view.h │ │ │ │ ├── bar_chart_view.cpp │ │ │ │ ├── bar_chart_view.h │ │ │ │ ├── chart_rulers_view.cpp │ │ │ │ ├── chart_rulers_view.h │ │ │ │ ├── chart_view_factory.cpp │ │ │ │ ├── chart_view_factory.h │ │ │ │ ├── linear_chart_view.cpp │ │ │ │ ├── linear_chart_view.h │ │ │ │ ├── stack_chart_common.cpp │ │ │ │ ├── stack_chart_common.h │ │ │ │ ├── stack_linear_chart_common.cpp │ │ │ │ ├── stack_linear_chart_common.h │ │ │ │ ├── stack_linear_chart_view.cpp │ │ │ │ └── stack_linear_chart_view.h │ │ │ └── widgets/ │ │ │ ├── chart_header_widget.cpp │ │ │ ├── chart_header_widget.h │ │ │ ├── chart_lines_filter_widget.cpp │ │ │ ├── chart_lines_filter_widget.h │ │ │ ├── point_details_widget.cpp │ │ │ └── point_details_widget.h │ │ ├── stdafx.h │ │ ├── storage/ │ │ │ ├── details/ │ │ │ │ ├── storage_file_utilities.cpp │ │ │ │ ├── storage_file_utilities.h │ │ │ │ ├── storage_settings_scheme.cpp │ │ │ │ └── storage_settings_scheme.h │ │ │ ├── download_manager_mtproto.cpp │ │ │ ├── download_manager_mtproto.h │ │ │ ├── file_download.cpp │ │ │ ├── file_download.h │ │ │ ├── file_download_mtproto.cpp │ │ │ ├── file_download_mtproto.h │ │ │ ├── file_download_web.cpp │ │ │ ├── file_download_web.h │ │ │ ├── file_upload.cpp │ │ │ ├── file_upload.h │ │ │ ├── localimageloader.cpp │ │ │ ├── localimageloader.h │ │ │ ├── localstorage.cpp │ │ │ ├── localstorage.h │ │ │ ├── serialize_common.cpp │ │ │ ├── serialize_common.h │ │ │ ├── serialize_document.cpp │ │ │ ├── serialize_document.h │ │ │ ├── serialize_peer.cpp │ │ │ ├── serialize_peer.h │ │ │ ├── storage_account.cpp │ │ │ ├── storage_account.h │ │ │ ├── storage_cloud_blob.cpp │ │ │ ├── storage_cloud_blob.h │ │ │ ├── storage_domain.cpp │ │ │ ├── storage_domain.h │ │ │ ├── storage_facade.cpp │ │ │ ├── storage_facade.h │ │ │ ├── storage_file_lock.h │ │ │ ├── storage_file_lock_posix.cpp │ │ │ ├── storage_file_lock_win.cpp │ │ │ ├── storage_media_prepare.cpp │ │ │ ├── storage_media_prepare.h │ │ │ ├── storage_shared_media.cpp │ │ │ ├── storage_shared_media.h │ │ │ ├── storage_sparse_ids_list.cpp │ │ │ ├── storage_sparse_ids_list.h │ │ │ ├── storage_user_photos.cpp │ │ │ ├── storage_user_photos.h │ │ │ ├── streamed_file_downloader.cpp │ │ │ └── streamed_file_downloader.h │ │ ├── support/ │ │ │ ├── support_autocomplete.cpp │ │ │ ├── support_autocomplete.h │ │ │ ├── support_common.cpp │ │ │ ├── support_common.h │ │ │ ├── support_helper.cpp │ │ │ ├── support_helper.h │ │ │ ├── support_preload.cpp │ │ │ ├── support_preload.h │ │ │ ├── support_templates.cpp │ │ │ └── support_templates.h │ │ ├── tde2e/ │ │ │ ├── tde2e_api.cpp │ │ │ ├── tde2e_api.h │ │ │ ├── tde2e_integration.cpp │ │ │ └── tde2e_integration.h │ │ ├── tests/ │ │ │ ├── test_main.cpp │ │ │ ├── test_main.h │ │ │ └── test_text.cpp │ │ ├── tray.cpp │ │ ├── tray.h │ │ ├── tray_accounts_menu.cpp │ │ ├── tray_accounts_menu.h │ │ ├── tray_accounts_menu_dummy.cpp │ │ ├── ui/ │ │ │ ├── boxes/ │ │ │ │ ├── about_cocoon_box.cpp │ │ │ │ ├── about_cocoon_box.h │ │ │ │ ├── auto_delete_settings.cpp │ │ │ │ ├── auto_delete_settings.h │ │ │ │ ├── boost_box.cpp │ │ │ │ ├── boost_box.h │ │ │ │ ├── calendar_box.cpp │ │ │ │ ├── calendar_box.h │ │ │ │ ├── choose_date_time.cpp │ │ │ │ ├── choose_date_time.h │ │ │ │ ├── choose_font_box.cpp │ │ │ │ ├── choose_font_box.h │ │ │ │ ├── choose_language_box.cpp │ │ │ │ ├── choose_language_box.h │ │ │ │ ├── choose_time.cpp │ │ │ │ ├── choose_time.h │ │ │ │ ├── collectible_info_box.cpp │ │ │ │ ├── collectible_info_box.h │ │ │ │ ├── confirm_box.cpp │ │ │ │ ├── confirm_box.h │ │ │ │ ├── confirm_phone_box.cpp │ │ │ │ ├── confirm_phone_box.h │ │ │ │ ├── country_select_box.cpp │ │ │ │ ├── country_select_box.h │ │ │ │ ├── edit_birthday_box.cpp │ │ │ │ ├── edit_birthday_box.h │ │ │ │ ├── edit_factcheck_box.cpp │ │ │ │ ├── edit_factcheck_box.h │ │ │ │ ├── edit_invite_link.cpp │ │ │ │ ├── edit_invite_link.h │ │ │ │ ├── edit_invite_link_session.cpp │ │ │ │ ├── edit_invite_link_session.h │ │ │ │ ├── emoji_stake_box.cpp │ │ │ │ ├── emoji_stake_box.h │ │ │ │ ├── peer_qr_box.cpp │ │ │ │ ├── peer_qr_box.h │ │ │ │ ├── rate_call_box.cpp │ │ │ │ ├── rate_call_box.h │ │ │ │ ├── report_box_graphics.cpp │ │ │ │ ├── report_box_graphics.h │ │ │ │ ├── show_or_premium_box.cpp │ │ │ │ ├── show_or_premium_box.h │ │ │ │ ├── single_choice_box.cpp │ │ │ │ ├── single_choice_box.h │ │ │ │ ├── time_picker_box.cpp │ │ │ │ └── time_picker_box.h │ │ │ ├── cached_round_corners.cpp │ │ │ ├── cached_round_corners.h │ │ │ ├── chat/ │ │ │ │ ├── attach/ │ │ │ │ │ ├── attach_abstract_single_file_preview.cpp │ │ │ │ │ ├── attach_abstract_single_file_preview.h │ │ │ │ │ ├── attach_abstract_single_media_preview.cpp │ │ │ │ │ ├── attach_abstract_single_media_preview.h │ │ │ │ │ ├── attach_abstract_single_preview.h │ │ │ │ │ ├── attach_album_preview.cpp │ │ │ │ │ ├── attach_album_preview.h │ │ │ │ │ ├── attach_album_thumbnail.cpp │ │ │ │ │ ├── attach_album_thumbnail.h │ │ │ │ │ ├── attach_bot_downloads.cpp │ │ │ │ │ ├── attach_bot_downloads.h │ │ │ │ │ ├── attach_bot_webview.cpp │ │ │ │ │ ├── attach_bot_webview.h │ │ │ │ │ ├── attach_controls.cpp │ │ │ │ │ ├── attach_controls.h │ │ │ │ │ ├── attach_extensions.cpp │ │ │ │ │ ├── attach_extensions.h │ │ │ │ │ ├── attach_item_single_file_preview.cpp │ │ │ │ │ ├── attach_item_single_file_preview.h │ │ │ │ │ ├── attach_item_single_media_preview.cpp │ │ │ │ │ ├── attach_item_single_media_preview.h │ │ │ │ │ ├── attach_prepare.cpp │ │ │ │ │ ├── attach_prepare.h │ │ │ │ │ ├── attach_send_files_way.cpp │ │ │ │ │ ├── attach_send_files_way.h │ │ │ │ │ ├── attach_single_file_preview.cpp │ │ │ │ │ ├── attach_single_file_preview.h │ │ │ │ │ ├── attach_single_media_preview.cpp │ │ │ │ │ └── attach_single_media_preview.h │ │ │ │ ├── chat.style │ │ │ │ ├── chat_style.cpp │ │ │ │ ├── chat_style.h │ │ │ │ ├── chat_style_radius.cpp │ │ │ │ ├── chat_style_radius.h │ │ │ │ ├── chat_theme.cpp │ │ │ │ ├── chat_theme.h │ │ │ │ ├── chats_filter_tag.cpp │ │ │ │ ├── chats_filter_tag.h │ │ │ │ ├── choose_send_as.cpp │ │ │ │ ├── choose_send_as.h │ │ │ │ ├── choose_theme_controller.cpp │ │ │ │ ├── choose_theme_controller.h │ │ │ │ ├── continuous_scroll.cpp │ │ │ │ ├── continuous_scroll.h │ │ │ │ ├── forward_options_box.cpp │ │ │ │ ├── forward_options_box.h │ │ │ │ ├── group_call_bar.cpp │ │ │ │ ├── group_call_bar.h │ │ │ │ ├── group_call_userpics.cpp │ │ │ │ ├── group_call_userpics.h │ │ │ │ ├── message_bar.cpp │ │ │ │ ├── message_bar.h │ │ │ │ ├── message_bubble.cpp │ │ │ │ ├── message_bubble.h │ │ │ │ ├── more_chats_bar.cpp │ │ │ │ ├── more_chats_bar.h │ │ │ │ ├── pinned_bar.cpp │ │ │ │ ├── pinned_bar.h │ │ │ │ ├── requests_bar.cpp │ │ │ │ ├── requests_bar.h │ │ │ │ ├── sponsored_message_bar.cpp │ │ │ │ └── sponsored_message_bar.h │ │ │ ├── color_contrast.cpp │ │ │ ├── color_contrast.h │ │ │ ├── color_indices.style │ │ │ ├── color_int_conversion.cpp │ │ │ ├── color_int_conversion.h │ │ │ ├── controls/ │ │ │ │ ├── button_labels.cpp │ │ │ │ ├── button_labels.h │ │ │ │ ├── call_mute_button.cpp │ │ │ │ ├── call_mute_button.h │ │ │ │ ├── chat_service_checkbox.cpp │ │ │ │ ├── chat_service_checkbox.h │ │ │ │ ├── compose_ai_button_factory.cpp │ │ │ │ ├── compose_ai_button_factory.h │ │ │ │ ├── delete_message_context_action.cpp │ │ │ │ ├── delete_message_context_action.h │ │ │ │ ├── download_bar.cpp │ │ │ │ ├── download_bar.h │ │ │ │ ├── dynamic_images_strip.cpp │ │ │ │ ├── dynamic_images_strip.h │ │ │ │ ├── emoji_button.cpp │ │ │ │ ├── emoji_button.h │ │ │ │ ├── emoji_button_factory.cpp │ │ │ │ ├── emoji_button_factory.h │ │ │ │ ├── feature_list.cpp │ │ │ │ ├── feature_list.h │ │ │ │ ├── filter_link_header.cpp │ │ │ │ ├── filter_link_header.h │ │ │ │ ├── invite_link_buttons.cpp │ │ │ │ ├── invite_link_buttons.h │ │ │ │ ├── invite_link_label.cpp │ │ │ │ ├── invite_link_label.h │ │ │ │ ├── jump_down_button.cpp │ │ │ │ ├── jump_down_button.h │ │ │ │ ├── labeled_emoji_tabs.cpp │ │ │ │ ├── labeled_emoji_tabs.h │ │ │ │ ├── location_picker.cpp │ │ │ │ ├── location_picker.h │ │ │ │ ├── peer_list_dummy.cpp │ │ │ │ ├── peer_list_dummy.h │ │ │ │ ├── popup_selector.cpp │ │ │ │ ├── popup_selector.h │ │ │ │ ├── round_video_recorder.cpp │ │ │ │ ├── round_video_recorder.h │ │ │ │ ├── round_video_recorder_data.h │ │ │ │ ├── send_as_button.cpp │ │ │ │ ├── send_as_button.h │ │ │ │ ├── send_button.cpp │ │ │ │ ├── send_button.h │ │ │ │ ├── silent_toggle.cpp │ │ │ │ ├── silent_toggle.h │ │ │ │ ├── stars_rating.cpp │ │ │ │ ├── stars_rating.h │ │ │ │ ├── sub_tabs.cpp │ │ │ │ ├── sub_tabs.h │ │ │ │ ├── subsection_tabs_slider.cpp │ │ │ │ ├── subsection_tabs_slider.h │ │ │ │ ├── subsection_tabs_slider_reorder.cpp │ │ │ │ ├── subsection_tabs_slider_reorder.h │ │ │ │ ├── swipe_handler.cpp │ │ │ │ ├── swipe_handler.h │ │ │ │ ├── swipe_handler_data.h │ │ │ │ ├── tabbed_search.cpp │ │ │ │ ├── tabbed_search.h │ │ │ │ ├── table_rows.cpp │ │ │ │ ├── table_rows.h │ │ │ │ ├── ton_common.cpp │ │ │ │ ├── ton_common.h │ │ │ │ ├── userpic_button.cpp │ │ │ │ ├── userpic_button.h │ │ │ │ ├── who_reacted_context_action.cpp │ │ │ │ ├── who_reacted_context_action.h │ │ │ │ ├── window_outdated_bar.cpp │ │ │ │ ├── window_outdated_bar.h │ │ │ │ ├── window_outdated_bar_dummy.cpp │ │ │ │ ├── window_screen_reader_bar.cpp │ │ │ │ └── window_screen_reader_bar.h │ │ │ ├── countryinput.cpp │ │ │ ├── countryinput.h │ │ │ ├── dynamic_thumbnails.cpp │ │ │ ├── dynamic_thumbnails.h │ │ │ ├── effects/ │ │ │ │ ├── credits.style │ │ │ │ ├── credits_graphics.cpp │ │ │ │ ├── credits_graphics.h │ │ │ │ ├── emoji_fly_animation.cpp │ │ │ │ ├── emoji_fly_animation.h │ │ │ │ ├── fireworks_animation.cpp │ │ │ │ ├── fireworks_animation.h │ │ │ │ ├── glare.cpp │ │ │ │ ├── glare.h │ │ │ │ ├── loading_element.cpp │ │ │ │ ├── loading_element.h │ │ │ │ ├── message_sending_animation_common.h │ │ │ │ ├── message_sending_animation_controller.cpp │ │ │ │ ├── message_sending_animation_controller.h │ │ │ │ ├── ministar_particles.cpp │ │ │ │ ├── ministar_particles.h │ │ │ │ ├── outline_segments.cpp │ │ │ │ ├── outline_segments.h │ │ │ │ ├── premium.style │ │ │ │ ├── premium_bubble.cpp │ │ │ │ ├── premium_bubble.h │ │ │ │ ├── premium_graphics.cpp │ │ │ │ ├── premium_graphics.h │ │ │ │ ├── premium_stars.cpp │ │ │ │ ├── premium_stars.h │ │ │ │ ├── premium_stars_colored.cpp │ │ │ │ ├── premium_stars_colored.h │ │ │ │ ├── premium_top_bar.cpp │ │ │ │ ├── premium_top_bar.h │ │ │ │ ├── reaction_fly_animation.cpp │ │ │ │ ├── reaction_fly_animation.h │ │ │ │ ├── round_checkbox.cpp │ │ │ │ ├── round_checkbox.h │ │ │ │ ├── scroll_content_shadow.cpp │ │ │ │ ├── scroll_content_shadow.h │ │ │ │ ├── send_action_animations.cpp │ │ │ │ ├── send_action_animations.h │ │ │ │ ├── shake_animation.cpp │ │ │ │ ├── shake_animation.h │ │ │ │ ├── skeleton_animation.cpp │ │ │ │ ├── skeleton_animation.h │ │ │ │ ├── snowflakes.cpp │ │ │ │ ├── snowflakes.h │ │ │ │ ├── thanos_effect.cpp │ │ │ │ ├── thanos_effect.h │ │ │ │ ├── thanos_effect_controller.cpp │ │ │ │ ├── thanos_effect_controller.h │ │ │ │ ├── thanos_effect_renderer.cpp │ │ │ │ ├── thanos_effect_renderer.h │ │ │ │ ├── thanos_effect_session.cpp │ │ │ │ ├── thanos_effect_session.h │ │ │ │ ├── toggle_arrow.cpp │ │ │ │ ├── toggle_arrow.h │ │ │ │ ├── ttl_icon.cpp │ │ │ │ ├── ttl_icon.h │ │ │ │ ├── upload_progress_overlay.cpp │ │ │ │ └── upload_progress_overlay.h │ │ │ ├── empty_userpic.cpp │ │ │ ├── empty_userpic.h │ │ │ ├── filter_icon_panel.cpp │ │ │ ├── filter_icon_panel.h │ │ │ ├── filter_icons.cpp │ │ │ ├── filter_icons.h │ │ │ ├── filter_icons.style │ │ │ ├── grouped_layout.cpp │ │ │ ├── grouped_layout.h │ │ │ ├── image/ │ │ │ │ ├── image.cpp │ │ │ │ ├── image.h │ │ │ │ ├── image_location.cpp │ │ │ │ ├── image_location.h │ │ │ │ ├── image_location_factory.cpp │ │ │ │ ├── image_location_factory.h │ │ │ │ ├── image_source.cpp │ │ │ │ ├── svg_preview.cpp │ │ │ │ └── svg_preview.h │ │ │ ├── item_text_options.cpp │ │ │ ├── item_text_options.h │ │ │ ├── menu_icons.style │ │ │ ├── new_badges.cpp │ │ │ ├── new_badges.h │ │ │ ├── peer/ │ │ │ │ ├── color_sample.cpp │ │ │ │ ├── color_sample.h │ │ │ │ ├── video_userpic_player.cpp │ │ │ │ └── video_userpic_player.h │ │ │ ├── power_saving.cpp │ │ │ ├── power_saving.h │ │ │ ├── resize_area.h │ │ │ ├── search_field_controller.cpp │ │ │ ├── search_field_controller.h │ │ │ ├── td_common.style │ │ │ ├── text/ │ │ │ │ ├── format_song_document_name.cpp │ │ │ │ ├── format_song_document_name.h │ │ │ │ ├── format_song_name.cpp │ │ │ │ ├── format_song_name.h │ │ │ │ ├── format_values.cpp │ │ │ │ ├── format_values.h │ │ │ │ ├── text_lottie_custom_emoji.cpp │ │ │ │ ├── text_lottie_custom_emoji.h │ │ │ │ ├── text_options.cpp │ │ │ │ └── text_options.h │ │ │ ├── top_background_gradient.cpp │ │ │ ├── top_background_gradient.h │ │ │ ├── ui_pch.h │ │ │ ├── unread_badge.cpp │ │ │ ├── unread_badge.h │ │ │ ├── unread_badge_paint.cpp │ │ │ ├── unread_badge_paint.h │ │ │ ├── unread_counter_format.cpp │ │ │ ├── unread_counter_format.h │ │ │ ├── userpic_view.cpp │ │ │ ├── userpic_view.h │ │ │ ├── vertical_list.cpp │ │ │ ├── vertical_list.h │ │ │ ├── webview_helpers.cpp │ │ │ ├── webview_helpers.h │ │ │ └── widgets/ │ │ │ ├── chat_filters_tabs_slider.cpp │ │ │ ├── chat_filters_tabs_slider.h │ │ │ ├── chat_filters_tabs_slider_reorder.cpp │ │ │ ├── chat_filters_tabs_slider_reorder.h │ │ │ ├── chat_filters_tabs_strip.cpp │ │ │ ├── chat_filters_tabs_strip.h │ │ │ ├── color_editor.cpp │ │ │ ├── color_editor.h │ │ │ ├── continuous_sliders.cpp │ │ │ ├── continuous_sliders.h │ │ │ ├── cross_fade_label.cpp │ │ │ ├── cross_fade_label.h │ │ │ ├── discrete_sliders.cpp │ │ │ ├── discrete_sliders.h │ │ │ ├── expandable_peer_list.cpp │ │ │ ├── expandable_peer_list.h │ │ │ ├── fields/ │ │ │ │ ├── special_fields.cpp │ │ │ │ ├── special_fields.h │ │ │ │ ├── time_part_input_with_placeholder.cpp │ │ │ │ └── time_part_input_with_placeholder.h │ │ │ ├── gradient_round_button.cpp │ │ │ ├── gradient_round_button.h │ │ │ ├── horizontal_fit_container.cpp │ │ │ ├── horizontal_fit_container.h │ │ │ ├── level_meter.cpp │ │ │ ├── level_meter.h │ │ │ ├── middle_click_autoscroll.cpp │ │ │ ├── middle_click_autoscroll.h │ │ │ ├── multi_select.cpp │ │ │ ├── multi_select.h │ │ │ ├── participants_check_view.cpp │ │ │ ├── participants_check_view.h │ │ │ ├── peer_bubble.cpp │ │ │ ├── peer_bubble.h │ │ │ ├── sent_code_field.cpp │ │ │ ├── sent_code_field.h │ │ │ ├── slider_natural_width.h │ │ │ ├── vertical_drum_picker.cpp │ │ │ └── vertical_drum_picker.h │ │ └── window/ │ │ ├── main_window.cpp │ │ ├── main_window.h │ │ ├── notifications_manager.cpp │ │ ├── notifications_manager.h │ │ ├── notifications_manager_default.cpp │ │ ├── notifications_manager_default.h │ │ ├── notifications_utilities.cpp │ │ ├── notifications_utilities.h │ │ ├── section_memento.h │ │ ├── section_widget.cpp │ │ ├── section_widget.h │ │ ├── session/ │ │ │ └── window_session_media.cpp │ │ ├── themes/ │ │ │ ├── window_theme.cpp │ │ │ ├── window_theme.h │ │ │ ├── window_theme_editor.cpp │ │ │ ├── window_theme_editor.h │ │ │ ├── window_theme_editor_block.cpp │ │ │ ├── window_theme_editor_block.h │ │ │ ├── window_theme_editor_box.cpp │ │ │ ├── window_theme_editor_box.h │ │ │ ├── window_theme_preview.cpp │ │ │ ├── window_theme_preview.h │ │ │ ├── window_theme_warning.cpp │ │ │ ├── window_theme_warning.h │ │ │ ├── window_themes_cloud_list.cpp │ │ │ ├── window_themes_cloud_list.h │ │ │ ├── window_themes_embedded.cpp │ │ │ ├── window_themes_embedded.h │ │ │ ├── window_themes_generate_name.cpp │ │ │ └── window_themes_generate_name.h │ │ ├── window.style │ │ ├── window_adaptive.cpp │ │ ├── window_adaptive.h │ │ ├── window_chat_preview.cpp │ │ ├── window_chat_preview.h │ │ ├── window_chat_switch_process.cpp │ │ ├── window_chat_switch_process.h │ │ ├── window_connecting_widget.cpp │ │ ├── window_connecting_widget.h │ │ ├── window_controller.cpp │ │ ├── window_controller.h │ │ ├── window_filters_menu.cpp │ │ ├── window_filters_menu.h │ │ ├── window_history_hider.cpp │ │ ├── window_history_hider.h │ │ ├── window_lock_widgets.cpp │ │ ├── window_lock_widgets.h │ │ ├── window_main_menu.cpp │ │ ├── window_main_menu.h │ │ ├── window_main_menu_helpers.cpp │ │ ├── window_main_menu_helpers.h │ │ ├── window_media_preview.cpp │ │ ├── window_media_preview.h │ │ ├── window_peer_menu.cpp │ │ ├── window_peer_menu.h │ │ ├── window_section_common.h │ │ ├── window_separate_id.cpp │ │ ├── window_separate_id.h │ │ ├── window_session_controller.cpp │ │ ├── window_session_controller.h │ │ ├── window_session_controller_link_info.h │ │ ├── window_setup_email.cpp │ │ ├── window_setup_email.h │ │ ├── window_slide_animation.cpp │ │ ├── window_slide_animation.h │ │ └── window_top_bar_wrap.h │ ├── Telegram/ │ │ ├── Breakpad.entitlements │ │ ├── Images.xcassets/ │ │ │ └── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Telegram Lite.entitlements │ │ └── Telegram.entitlements │ ├── Telegram.plist │ ├── ThirdParty/ │ │ └── minizip/ │ │ ├── crypt.h │ │ ├── ioapi.c │ │ ├── ioapi.h │ │ ├── unzip.c │ │ ├── unzip.h │ │ ├── zip.c │ │ └── zip.h │ ├── build/ │ │ ├── build.bat │ │ ├── build.sh │ │ ├── changelog2appstream.py │ │ ├── deploy.sh │ │ ├── docker/ │ │ │ ├── build.sh │ │ │ └── centos_env/ │ │ │ ├── .gitignore │ │ │ ├── Dockerfile │ │ │ ├── build.sh │ │ │ ├── centos_env/ │ │ │ │ └── __init__.py │ │ │ ├── gen_dockerfile.py │ │ │ ├── pyproject.toml │ │ │ └── run.sh │ │ ├── mac_store_upload.sh │ │ ├── prepare/ │ │ │ ├── linux.sh │ │ │ ├── mac.sh │ │ │ ├── prepare.py │ │ │ └── win.bat │ │ ├── qt_version.py │ │ ├── release.py │ │ ├── release.sh │ │ ├── replace.vbs │ │ ├── set_version.bat │ │ ├── set_version.py │ │ ├── set_version.sh │ │ ├── setup.iss │ │ ├── test_package.bat │ │ ├── updates.py │ │ ├── updates.sh │ │ └── version │ ├── cmake/ │ │ ├── generate_appstream_changelog.cmake │ │ ├── generate_lang.cmake │ │ ├── generate_midl.cmake │ │ ├── generate_numbers.cmake │ │ ├── generate_scheme.cmake │ │ ├── lib_ffmpeg.cmake │ │ ├── lib_prisma.cmake │ │ ├── lib_stripe.cmake │ │ ├── lib_tgcalls.cmake │ │ ├── qrhi_shaders.cmake │ │ ├── td_export.cmake │ │ ├── td_forkgram.cmake │ │ ├── td_iv.cmake │ │ ├── td_lang.cmake │ │ ├── td_mtproto.cmake │ │ ├── td_scheme.cmake │ │ ├── td_tde2e.cmake │ │ ├── td_ui.cmake │ │ ├── telegram_apple_swift_runtime.cmake │ │ ├── telegram_options.cmake │ │ └── tests.cmake │ ├── configure.bat │ ├── configure.py │ ├── configure.sh │ ├── create.bat │ ├── gyp/ │ │ └── telegram/ │ │ └── sources.txt │ └── shaders/ │ ├── argb32.frag │ ├── argb32.vert │ ├── blur_h.frag │ ├── blur_v.frag │ ├── controls.frag │ ├── demo.frag │ ├── demo.vert │ ├── fill.frag │ ├── fill.vert │ ├── group_frame.frag │ ├── group_frame.vert │ ├── incoming_shadow.frag │ ├── incoming_yuv420.frag │ ├── noise.frag │ ├── nv12.frag │ ├── nv12_content.frag │ ├── passthrough.vert │ ├── pip_argb32.frag │ ├── pip_controls.frag │ ├── pip_controls.vert │ ├── pip_nv12.frag │ ├── pip_yuv420.frag │ ├── rounded_corners.frag │ ├── static_content.frag │ ├── thanos.frag │ ├── thanos.vert │ ├── thanos_init.comp │ ├── thanos_update.comp │ ├── transparent_content.frag │ ├── yuv420.frag │ └── yuv420_content.frag ├── _config_github_pages.yml ├── changelog.txt ├── docs/ │ ├── api_credentials.md │ ├── building-linux.md │ ├── building-mac.md │ ├── building-mas.md │ ├── building-win.md │ └── misc.txt ├── index.html ├── lib/ │ └── xdg/ │ ├── org.telegram.desktop.desktop │ ├── org.telegram.desktop.metainfo.xml │ └── org.telegram.desktop.service ├── patches/ │ ├── cmake_qt611.patch │ └── cmake_zbar.patch └── snap/ └── snapcraft.yaml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .agents/skills/task-think/PROMPTS.md ================================================ # Phase Prompts Use these templates as Codex subagent messages. Use them as same-session checklists only for Phase 0, intentional main-session build work, Phase 7, or when delegation is unavailable from the start. Replace ``, ``, ``, and ``. ## Orchestration Rules - Phase 0 runs in the main session. - When delegation is available, use a fresh subagent for Phase 1, Phase 2, Phase 3, each Phase 4 implementation unit, and each Phase 6 pass. Do not switch those phases to same-session midstream because of a timeout or missing artifact. - Phase 7 runs in the main session on Windows because it depends on the final local diff and touched-file set. - Write each phase prompt to `.ai///logs/phase-.prompt.md` before execution. - If you delegate a phase, send the prompt file contents as the initial `spawn_agent` message. - When writing the phase prompt file, append the standard progress file contract and the standard compact reply block below so the subagent knows how to surface progress before the final artifact. - After each phase completes, write `.ai///logs/phase-.result.md` summarizing the status, files touched, and any follow-up notes. - Use `fork_context: false` by default. If the phase depends on thread-only context or UI attachments, pass that context explicitly or enable `fork_context` only for that phase. - Prefer `worker` for phases that write files. Use `default` for plan or review passes if that fits the host better. Use `explorer` only for narrow read-only questions. - When supported, request `model: gpt-5.4` and `reasoning_effort: xhigh` for delegated phases. - Default wait budget for delegated phases is 5 minutes while the phase is clearly still in progress. Successful completion may wake earlier, so this does not delay finished work. - When a phase appears close to landing, use 1-2 minute waits until it finishes. - A `wait_agent` timeout is not failure. On timeout, inspect both the expected artifact and the matching progress file before deciding anything. - If the expected artifact exists and shows progress, wait again. - If the expected artifact is not ready but the progress file mtime moved or its heartbeat counter increased since the previous check, wait again. Prefer mtime checks first and avoid rereading the file unless you need detail. Do not count that as a failed wait. - If neither the expected artifact nor the progress file moved since the previous blocked check, send one short follow-up asking the same agent to refresh the progress file, finish the required artifact, and return the standard compact reply block, then wait again. - If the same agent still produces no usable artifact and no meaningful progress-file movement after two full default waits and one follow-up, close it and retry the phase in a fresh subagent. - For Phase 1, Phase 2, Phase 3, Phase 4, and Phase 6, if delegated retries still fail, stop and ask the user rather than rerunning the phase locally. - Never use `codex exec`, background shell child processes, or JSONL child-session logging from this skill. ## Standard Progress File Contract Append this verbatim to every delegated phase prompt: ```text Before deep work, create or update the matching progress file in `.ai///logs/`. Use `.progress.md` as a concise heartbeat with: - `Heartbeat: ` on the first line, incremented on each meaningful update - Current step - Files being read or edited - Concrete findings or decisions so far - Blocker or next checkpoint Update it sparingly: preferably at natural milestones, and otherwise only after a longer quiet stretch such as roughly 5-10 minutes. Keep it tiny so the parent can usually rely on file mtime or the heartbeat counter instead of rereading the whole file. Do not wait until the final artifact to write progress. ``` ## Standard Compact Reply Block Append this verbatim to every delegated phase prompt: ```text Before replying in chat, write the required artifact(s) to disk. Reply in 8 lines or fewer using exactly these keys: STATUS: ARTIFACTS: TOUCHED: BLOCKER: Do not restate the full context, plan, diff, or long reasoning in the chat reply. ``` ## Artifact-Based Completion Checks - Phase 1 is complete only when `about.md` and `context.md` both exist and are non-empty. - Phase 2 is complete only when `plan.md` exists, contains a `## Status` section, and no unintended source edits were made. - Phase 3 is complete only when `plan.md` contains both `Phases:` in the Status section and `Assessed: yes`. - Phase 4 is complete only when the target phase checkbox changed to checked and the touched-file list matches the owned write set, or the blocker explains any mismatch. - Phase 5 is complete only when the build outcome is known and the build checkbox is updated on success. - Phase 6a is complete only when `review.md` exists and contains a verdict line. - Phase 6b is complete only when the requested fixes were applied and the post-fix build outcome is known. ## Phase 0: Setup Record the current time now and store it as `$START_TIME`. You will use this at the end to display total elapsed time. Before running any phase prompts, determine whether this is a new project or a follow-up task. Follow-up detection: 1. Extract the first word or token from the task description. Call it `FIRST_TOKEN`. 2. Check `.ai/` to see existing project names. 3. Check whether `.ai//about.md` exists. 4. If the file exists, this is a follow-up task. The project name is `FIRST_TOKEN`. The task description is everything after `FIRST_TOKEN`. 5. If the file does not exist, this is a new project. The full input is the task description. Do not proceed until you have determined follow-up vs new. For new projects: - Using the list of existing projects, pick a unique short name (1-2 lowercase words, hyphen-separated) that does not collide. - Create `.ai//`, `.ai//a/`, and `.ai//a/logs/`. - Set `` = `a`. For follow-up tasks: - Scan `.ai//` for existing task folders (`a/`, `b/`, ...). Find the latest one (highest letter). - The previous task letter = that highest letter. - The new task letter = next letter in sequence. - Create `.ai///` and `.ai///logs/`. Then proceed to Phase 1. Follow-up tasks do not skip context gathering. They use a modified Phase 1F prompt. ## Phase 1: Context (New Project, letter = `a`) ```text You are a context-gathering agent for a large C++ codebase (Telegram Desktop). TASK: YOUR JOB: Read AGENTS.md, inspect the codebase, find all files and code relevant to this task, and write two documents. Steps: 1. Read AGENTS.md for project conventions and build instructions. 2. Search the codebase for files, classes, functions, and patterns related to the task. 3. Read all potentially relevant files. Be thorough and prefer reading more rather than less. 4. For each relevant file, note: - file path - relevant line ranges - what the code does and how it relates to the task - key data structures, function signatures, and patterns used 5. Look for similar existing features that could serve as a reference implementation. 6. Check api.tl if the task involves Telegram API. 7. Check .style files if the task involves UI. 8. Check lang.strings if the task involves user-visible text. Write two files. File 1: .ai//about.md This file is not used by any agent in the current task. It exists solely as a starting point for a future follow-up task's context gatherer. No planning, implementation, or review phase should rely on it during the current task. Write it as if the project is already fully implemented and working. It should contain: - Project: What this project does (feature description, goals, scope) - Architecture: High-level architectural decisions, which modules are involved, how they interact - Key Design Decisions: Important choices made about the approach - Relevant Codebase Areas: Which parts of the codebase this project touches, key types and APIs involved Do not include temporal state like "Current State", "Pending Changes", "Not yet implemented", or "TODO". Describe the project as a complete, coherent whole. File 2: .ai//a/context.md This is the primary task-specific implementation context. All downstream phases should be able to work from this file plus the referenced source files. It must be self-contained. Include: - Task Description: The full task restated clearly - Relevant Files: Every file path with line ranges and descriptions - Key Code Patterns: How similar things are done in the codebase, with snippets when useful - Data Structures: Relevant types, structs, classes - API Methods: Any TL schema methods involved, copied from api.tl when useful - UI Styles: Any relevant style definitions - Localization: Any relevant string keys - Build Info: Build command and any special notes - Reference Implementations: Similar features that can serve as templates Be extremely thorough. Another agent with no prior context will rely on this file. Do not implement code in this phase. ``` ## Phase 1F: Context (Follow-up Task, letter = `b`, `c`, ...) ```text You are a context-gathering agent for a follow-up task on an existing project in a large C++ codebase (Telegram Desktop). NEW TASK: YOUR JOB: Read the existing project state, gather any additional context needed, and produce fresh documents for the new task. Steps: 1. Read AGENTS.md for project conventions and build instructions. 2. Read .ai//about.md. This is the project-level blueprint describing everything done so far. 3. Read .ai///context.md. This is the previous task's gathered context. 4. Understand what has already been implemented by reading the actual source files referenced in about.md and the previous context. 5. Based on the new task description, search the codebase for any additional files, classes, functions, and patterns that are relevant to the new task but not already covered. 6. Read all newly relevant files thoroughly. Write two files. File 1: .ai//about.md (rewrite) Rewrite this file instead of appending to it. The new about.md must be a single coherent document that describes the project as if everything, including this new task's changes, is already fully implemented and working. It should incorporate: - everything from the old about.md that is still accurate and relevant - the new task's functionality described as part of the project, not as a pending change - any changed design decisions or architectural updates from the new task requirements It should not contain: - temporal state such as "Current State", "Pending Changes", or "TODO" - history of how requirements changed between tasks - references to "the old approach" versus "the new approach" - task-by-task changelog or timeline - information that contradicts the new task requirements File 2: .ai///context.md This is the primary document for the new task. It must be self-contained and should include: - Task Description: The new task restated clearly, with enough project background that an implementation agent can understand it without reading any other .ai files - Relevant Files: Every file path with line ranges relevant to this task - Key Code Patterns: How similar things are done in the codebase - Data Structures: Relevant types, structs, classes - API Methods: Any TL schema methods involved - UI Styles: Any relevant style definitions - Localization: Any relevant string keys - Build Info: Build command and any special notes - Reference Implementations: Similar features that can serve as templates Be extremely thorough. Another agent with no prior context should be able to work from this file alone. Do not implement code in this phase. ``` ## Phase 2: Plan ```text You are a planning agent. You must create a detailed implementation plan. Read these files: - .ai///context.md - Then read the specific source files referenced in context.md to understand the code deeply. Create a detailed plan in: .ai///plan.md The plan.md should contain: ## Task ## Approach ## Files to Modify ## Files to Create ## Implementation Steps Each step must be specific enough that an agent can execute it without ambiguity: - exact file paths - exact function names - what code to add, modify, or remove - where exactly in the file (after which function, in which class, and so on) Number every step. Group steps into phases if there are more than about eight steps. ### Phase 1: 1. 2. ### Phase 2: (if needed) 1. ## Build Verification - build command to run - expected outcome ## Status - [ ] Phase 1: - [ ] Phase 2: (if applicable) - [ ] Build verification - [ ] Code review Do not implement code in this phase. ``` ## Phase 3: Plan Assessment ```text You are a plan assessment agent. Review and refine an implementation plan. Read these files: - .ai///context.md - .ai///plan.md - Then read the actual source files referenced to verify the plan makes sense. Assess the plan: 1. Correctness: Are the file paths and line references accurate? Does the plan reference real functions and types? 2. Completeness: Are there missing steps? Edge cases not handled? 3. Code quality: Will the plan minimize code duplication? Does it follow existing codebase patterns from AGENTS.md? 4. Design: Could the approach be improved? Are there better patterns already used in the codebase? 5. Phase sizing: Each phase should be implementable by a single agent in one session. If a phase has more than about 8-10 substantive code changes, split it further. Update plan.md with your refinements. Keep the same structure but: - fix any inaccuracies - add missing steps - improve the approach if you found better patterns - ensure phases are properly sized for single-agent execution - add a line at the top of the Status section: `Phases: ` - add `Assessed: yes` at the bottom of the file If the plan is small enough for a single agent (roughly 8 steps or fewer), mark it as a single phase. Do not implement code in this phase. ``` ## Phase 4: Implementation Run one implementation unit per plan phase. Keep implementation phases sequential by default. Parallelize only if their write sets are disjoint and the plan makes that safe. For each phase in the plan that is not yet marked as done, use this prompt: ```text You are an implementation agent working on phase of an implementation plan. Read these files first: - .ai///context.md - .ai///plan.md Then read the source files you will be modifying. Your owned write set for this phase: YOUR TASK: Implement only Phase from the plan: Rules: - Follow the plan precisely. - Follow AGENTS.md coding conventions. - You are not alone in the codebase. Respect existing changes and do not revert unrelated work. - Do not modify .ai/ files except to update the Status section in plan.md. - When done, update plan.md Status section: change `- [ ] Phase : ...` to `- [x] Phase : ...` - Do not work on other phases. When finished, report what you did, which files you changed, and any issues encountered. ``` After each implementation phase: 1. Use a narrow read or search to confirm the status line was updated. 2. Verify the owned write set and touched files with a small diff summary such as `git diff --name-only`. 3. If more phases remain, run the next implementation phase. 4. If all phases are done, proceed to build verification. ## Phase 5: Build Verification Only run this phase if the task modified project source code. Prefer running the build in the main session because it is critical-path work. If you delegate it, use a worker subagent and wait immediately for the result. ```text You are a build verification agent. Read these files: - .ai///context.md - .ai///plan.md The implementation is complete. Your job is to build the project and fix any build errors that block the planned work. Steps: 1. Run (from repository root): cmake --build ./out --config Debug --target Telegram 2. If the build succeeds, update plan.md: change `- [ ] Build verification` to `- [x] Build verification` 3. If the build fails: a. Read the error messages carefully b. Read the relevant source files c. Fix the errors in accordance with the plan and AGENTS.md conventions d. Rebuild and repeat until the build passes e. Update plan.md status when done Rules: - Only fix build errors. Do not refactor or improve code beyond what is needed for a passing build. - Follow AGENTS.md conventions. - If build fails with file-locked errors (C1041, LNK1104, "cannot open output file", or similar access-denied lock issues), stop and report the lock. Do not retry. - You are not alone in the codebase. Respect existing changes and do not revert unrelated work. When finished, report the build result and which files, if any, you changed. ``` ## Phase 6: Code Review Loop After build verification passes, run up to 3 review-fix iterations. Set iteration counter `R = 1`. Review loop: ```text LOOP: 1. Run review phase 6a with iteration R. 2. Read review.md verdict: - "APPROVED" -> go to FINISH - "NEEDS_CHANGES" -> run fix phase 6b 3. After fix work completes and build passes: R = R + 1 If R > 3 -> go to FINISH Otherwise -> go to step 1 FINISH: - Update plan.md: change `- [ ] Code review` to `- [x] Code review` - Proceed to Phase 7 on Windows, otherwise proceed to Completion ``` ### Step 6a: Code Review ```text You are a code review agent for Telegram Desktop (C++ / Qt). Read these files: - .ai///context.md - .ai///plan.md - REVIEW.md - If R > 1, also read .ai///review.md Then run `git diff` to see the current uncommitted changes for this task. Read the modified source files in full to understand the changes in context. Perform a focused code review using these criteria, in order: 1. Correctness and safety: Obvious logic errors, missing null checks at API boundaries, potential crashes, use-after-free, dangling references, race conditions. 2. Dead code: Added or left-behind code that is never used within the scope of the changes. 3. Redundant changes: Diff hunks that have no functional effect. 4. Code duplication: Repeated logic that should be shared. 5. Wrong placement: Code added to a module where it does not logically belong. 6. Function decomposition: Whether an extracted helper would clearly improve readability. 7. Module structure: Only in exceptional cases where a large new chunk of code clearly belongs elsewhere. 8. Style compliance: REVIEW.md rules and AGENTS.md conventions. Important guidelines: - Review only the changes made, not pre-existing code outside the scope of the task. - Be pragmatic. Each suggestion should have a clear, concrete benefit. - Do not suggest comments, docstrings, or over-engineering. Write your review to: .ai///review.md The review document should contain: ## Code Review - Iteration ## Summary <1-2 sentence overall assessment> ## Verdict: If the verdict is NEEDS_CHANGES, continue with: ## Changes Required ### - Category: - File(s): - Problem: - Fix: Keep the list focused. Prioritize the most impactful issues. When finished, report your verdict clearly as: APPROVED or NEEDS_CHANGES. ``` ### Step 6b: Review Fix ```text You are a review fix agent. You implement improvements identified during code review. Read these files: - .ai///context.md - .ai///plan.md - .ai///review.md Then read the source files mentioned in the review. YOUR TASK: Implement all changes listed in review.md. Rules: - Implement exactly the review changes, nothing more. - Follow AGENTS.md coding conventions. - You are not alone in the codebase. Respect existing changes and do not revert unrelated work. - Do not modify .ai/ files except where the review process explicitly requires it. After all changes are made: 1. Build (from repository root): cmake --build ./out --config Debug --target Telegram 2. If the build fails, fix build errors and rebuild until it passes. 3. If build fails with file-locked errors (C1041, LNK1104, "cannot open output file", or similar access-denied lock issues), stop and report the lock. Do not retry. When finished, report what changes were made and which files you touched. ``` ## Phase 7: Windows Text Normalization Run this phase only on Windows hosts and only after the review loop has finished. Use the current task's result logs as the source of truth for what Codex touched. Do not sweep the whole repo and do not rewrite unrelated files from a dirty worktree. ```text You are performing the final Windows-only text normalization phase for task-think. Read these files: - .ai///plan.md - .ai///logs/phase-4*.result.md - .ai///logs/phase-5*.result.md - .ai///logs/phase-6*.result.md Your job: - Collect the union of repo file paths listed under "Touched files" in those result logs. - Keep only files inside the repository that currently exist and are textual project files: source, headers, build/config files, localization files, style files, and similar text assets. - Exclude `.ai/`, `out/`, binary files, and unrelated user files that were not touched by Codex in this task. - Rewrite each kept file so all line endings are CRLF. - If a kept file is UTF-8 or ASCII text, write it back as UTF-8 without BOM. Never add a UTF-8 BOM to source/config/project text files. - Preserve file content otherwise. Preserve whether the file ended with a trailing newline. Rules: - Run this phase in the main session on Windows. - Do not modify files outside the touched-file set for the current task. - Do not rewrite binary files. - When scripting this phase, do not use writer APIs or defaults that emit UTF-8 with BOM. - If a file cannot be normalized safely, record it as a failure instead of silently skipping it. When finished: 1. Write `.ai///logs/phase-7-line-endings.result.md` 2. Include: - whether the phase completed - which files were normalized - which files were skipped and why - whether any UTF-8 BOMs were removed or verified absent - any failures that need to be mentioned in the final summary ``` ## Completion When all phases, including build verification, code review, and Windows line ending normalization when applicable, are done: 1. Read the final `plan.md` and report the summary to the user. 2. Show which files were modified or created. 3. Note any issues encountered during implementation. 4. Summarize the code review iterations: how many rounds, what was found and fixed, or whether it was approved on the first pass. 5. On Windows, mention the text-normalization result briefly: which project files were normalized, whether any BOMs were removed, or whether nothing needed changes. 6. Calculate and display the total elapsed time since `$START_TIME` (format as `Xh Ym Zs`, omitting zero components). 7. Remind the user of the project name so they can request follow-up tasks within the same project. ## Error Handling - If any phase fails or gets stuck, follow the timeout and retry rules above. Do not close an agent solely because the final artifact is missing while its progress file is still advancing. For Phase 1, Phase 2, Phase 3, Phase 4, and Phase 6, do not rerun locally after delegated retries fail; ask the user instead. - If `context.md` or `plan.md` is not written properly by a phase, rerun that phase in a fresh subagent with more specific instructions. - If build errors persist after the build phase's attempts, report the remaining errors to the user. - If a review-fix phase introduces new build errors that it cannot resolve, report to the user. ## Prompt Delivery And Logs For each phase: 1. Write the full prompt to `.ai///logs/phase-.prompt.md` 2. Delegate by sending that prompt text to a fresh subagent, or use it as a same-session checklist only for the designated main-session phases or when delegation was unavailable from the start 3. For delegated phases, expect a matching `.ai///logs/phase-.progress.md` heartbeat while work is in flight 4. Save a concise completion note to `.ai///logs/phase-.result.md` For review iterations, include the iteration in the file name, for example: - `phase-6a-review-1.prompt.md` - `phase-6a-review-1.result.md` - `phase-6b-fix-1.prompt.md` - `phase-6b-fix-1.result.md` ## Subagent Pattern Use this pattern conceptually for delegated phases: 1. Write the phase prompt file. 2. Spawn a fresh subagent with the phase prompt, usually with `fork_context: false`. 3. Require the agent to create the matching progress file early and refresh it sparingly: at natural milestones when possible, otherwise only after a longer quiet stretch such as roughly 5-10 minutes. 4. Wait in 5-minute intervals when the next step is blocked on that phase, checking both the final artifact and the progress file on timeout. 5. When the phase looks close to finishing, switch to 1-2 minute waits. 6. Prefer filesystem mtime checks on the progress file first. If its mtime moved or the heartbeat counter increased, keep waiting; do not treat that as a stall. 7. If neither the artifact nor the progress file moves, send one short follow-up to the same agent, then retry once with a fresh subagent before involving the user. 8. Validate the expected artifact or code changes with small shell summaries and the completion checks above. 9. Write the result log from the validated outcome and the compact reply block. Do not replace this pattern with shell-launched `codex exec`. ================================================ FILE: .agents/skills/task-think/SKILL.md ================================================ --- name: task-think description: Orchestrate a multi-phase implementation workflow for this repository with artifact files under .ai/// using Codex subagents instead of shell-spawned child processes. Use when the user wants one prompt to drive context gathering, planning, plan assessment, implementation, build verification, and review with persistent artifacts, clear phase handoffs, and a thin parent thread. Prefer spawn_agent/send_input/wait_agent, keep heavy pre-build work delegated when possible, and avoid pulling timed-out phases back into the main session. --- # Task Pipeline Run a full implementation workflow with repository artifacts and clear phase boundaries. ## Inputs Collect: - task description - optional project name (if missing, derive a short kebab-case name) - optional constraints (files, architecture, risk tolerance) - optional screenshot paths If screenshots are attached in UI but not present as files, write a brief textual summary into the task artifacts before spawning fresh subagents so later phases can read the requirements without inheriting the whole parent thread. ## Overview The workflow is organized around projects. Each project lives in `.ai//` and can contain multiple sequential tasks (labeled `a`, `b`, `c`, ... `z`). Project structure: ```text .ai// about.md # Single source of truth for the entire project a/ # First task context.md # Gathered codebase context for this task plan.md # Implementation plan review1.md # Code review documents (up to 3 iterations) review2.md review3.md logs/ phase-*.prompt.md phase-*.progress.md phase-*.result.md b/ # Follow-up task context.md plan.md review1.md logs/ ... c/ # Another follow-up task ... ``` - `about.md` is the project-level blueprint: a single comprehensive document describing what this project does and how it works, written as if everything is already fully implemented. It contains no temporal state ("current state", "pending changes", "not yet implemented"). It is rewritten, not appended to, each time a new task starts, incorporating the new task's changes as if they were always part of the design. - Each task folder (`a/`, `b/`, ...) contains self-contained files for that task. The task's `context.md` carries all task-specific information: what specifically needs to change, the delta from the current codebase, gathered file references, and code patterns. Planning, implementation, and review phases should rely on the current task folder. ## Artifacts Create and maintain: - `.ai//about.md` - `.ai///context.md` - `.ai///plan.md` - `.ai///review.md` (up to 3 review iterations) - `.ai///logs/phase-.prompt.md` - `.ai///logs/phase-.progress.md` for delegated phases - `.ai///logs/phase-.result.md` Each `phase-.result.md` should capture a concise outcome summary: whether the phase completed, which files it touched, and any follow-up notes or blockers. Each delegated `phase-.progress.md` should act as a heartbeat: a tiny monotonic counter plus current step, files being read or edited, concrete findings so far, and the next checkpoint. It is not a final artifact; it exists so the parent can distinguish active research from a truly stuck subagent without rereading large context. ## Phases Run these phases sequentially: 1. Phase 0: Setup - Record start time, detect follow-up vs new project, create directories. 2. Phase 1: Context Gathering - Read codebase, write `about.md` and `context.md`. Use Phase 1F for follow-up tasks. 3. Phase 2: Planning - Read context, write detailed `plan.md` with numbered steps grouped into phases. 4. Phase 3: Plan Assessment - Review and refine the plan for correctness, completeness, code quality, and phase sizing. 5. Phase 4: Implementation - Execute one implementation unit per plan phase. 6. Phase 5: Build Verification - Build the project, fix any build errors. Skip if no source code was modified. 7. Phase 6: Code Review Loop - Run review and fix iterations until approved or the iteration limit is reached. 8. Phase 7: Windows Text Normalization - On Windows only, after review passes and before the final summary, normalize LF to CRLF for the text source/config files Codex edited in this task and ensure rewritten UTF-8 project files are saved without BOM. Use the phase prompt templates in `PROMPTS.md`. ## Execution Mode Use Codex subagents as the primary orchestration mechanism. - When delegation is available, Phase 1, Phase 2, Phase 3, each Phase 4 implementation unit, and each Phase 6 review or review-fix pass must run in fresh subagents. Do not rerun those phases in the main session midstream just because a wait timed out or an artifact is missing. - Run Phase 7 in the main session on Windows because it depends on the final local file state and the exact touched-file set for the current task. - When any same-session helper rewrites Windows project text files, preserve CRLF and write UTF-8 without BOM. Avoid writer APIs or defaults that silently inject a UTF-8 BOM. - The main session may read `context.md` once after Phase 1 and `plan.md` once after Phase 3. After that, prefer narrow shell checks, file existence checks, and status-line reads instead of rereading full documents or diffs. - Prefer `worker` for phases that write files. Use `explorer` only for narrow read-only questions that unblock your next local step. - Keep `fork_context` off by default. Pass the phase prompt and explicit file paths instead of the whole thread unless the phase truly needs prior conversational context or thread-only attachments. - When the platform supports it, request `model: gpt-5.4` and `reasoning_effort: xhigh` for spawned phase agents. If overrides are unavailable, inherit the current session settings. - Write the exact phase prompt to the matching `logs/phase-.prompt.md` file before you delegate. Use the same prompt file as a checklist if you later need to fall back to same-session execution. - For delegated phases, require an early `logs/phase-.progress.md` heartbeat before deep work. The subagent should create or update it early, keep it tiny, and refresh it sparingly: preferably at natural milestones, and otherwise only after a longer quiet stretch such as roughly 5-10 minutes. - In every delegated prompt, require a compact final reply with only status, artifact paths, touched files, and blocker or `none`. Detailed reasoning belongs in `.ai/` artifacts, not in the chat reply. - After a subagent finishes, verify that the expected artifacts or code changes exist, then write a short result log in `logs/phase-.result.md`. - For delegated phases, use `wait_agent` with a 5-minute timeout by default while a phase is still clearly in progress. Successful completion may wake earlier, so this does not add latency to finished phases. - When a phase looks close to completion — for example the final artifact has appeared, a build is in its final pass, or the agent said it is wrapping up — switch to 1-2 minute waits until it lands. - A timeout is not a failure; it only means no final status arrived yet. Do not treat short waits as stall detection for research-heavy phases. - On timeout, inspect the expected artifact, the phase progress file mtime, and the worktree for movement. Prefer mtime checks first; only reread the progress file when you need detail. - If the progress file mtime moved or its heartbeat counter increased since the previous check, treat that as active progress and wait again. - If no usable final artifact exists yet but the progress file is appearing or advancing, keep the same subagent alive. Progress-file movement does not count toward the retry limit. - If no usable final artifact exists yet and neither the expected artifact nor the progress file has moved since the previous blocked check, send one short follow-up asking the same subagent to refresh the progress file, finish the artifact, and return the compact status block, then wait again. - Only if the same subagent still shows no meaningful movement in either the expected artifact or the progress file after two full default waits and one follow-up should you close it and rerun that phase in a fresh subagent. - Use `wait_agent` only when the next step is blocked on the result. While the delegated phase runs, do small non-overlapping local tasks such as validating directory structure or preparing the next prompt file. - Build verification is critical-path work. Prefer running the build in the main session, and only delegate a bounded build-fix phase when there is a concrete reason. - If subagents are unavailable in the current environment, or current policy does not allow delegation from the start, run the phase in the main session using the same prompt files. Otherwise, do not switch a pre-build phase to same-session midstream. Never fall back to shell-spawned `codex exec` child processes from this skill. ## Verification Rules - If build or test commands fail due to file locks or access-denied outputs (C1041, LNK1104), stop and ask the user to close locking processes before retrying. - Treat a delegated phase as complete only when the required artifact or status update exists on disk and matches the phase goals; do not rely on the chat reply alone. - Never claim completion without: - implemented code changes present - build attempt results recorded - review pass documented with any follow-up fixes - on Windows, if the task edited project source/config text files, a CRLF / no-BOM normalization pass recorded after review ## Completion Criteria Mark complete only when: - All plan phases are done - Build verification is recorded - Review issues are addressed or explicitly deferred with rationale - On Windows, Codex-edited project source/config text files have been normalized to CRLF, any UTF-8 rewrites were saved without BOM, and the result is logged - Display total elapsed time since start (format: `Xh Ym Zs`, omitting zero components) - Remind the user of the project name so they can request follow-up tasks within the same project ## Error Handling - If any phase fails, times out, or gets stuck, follow the retry ladder from Execution Mode. Do not close an agent solely because the final artifact is missing while its progress file is still moving. After two delegated attempts remain blocked with no meaningful progress, report the issue to the user. Do not absorb the phase into the main session before build unless delegation was unavailable from the start. - If `context.md` or `plan.md` is not written properly by a phase, rerun that phase in a fresh subagent with more specific instructions. Do not repair it locally before build unless delegation was unavailable from the start. - If build errors persist after the build phase's attempts, report the remaining errors to the user. - If a review-fix phase introduces new build errors that it cannot resolve, report to the user. - If Phase 7 cannot safely normalize a touched file on Windows or remove an introduced UTF-8 BOM from a touched project text file, record the failure in the result log and report it in the final summary instead of silently skipping it. ## User Invocation Use plain language with the skill name in the request, for example: `Use local task-think skill with subagents: make sure FileLoadTask::process does not create or read QPixmap on background threads; use QImage with ARGB32_Premultiplied instead.` For follow-up tasks on an existing project: `Use local task-think skill with subagents: my-project also handle the case where the file is already cached` If screenshots are relevant, include file paths in the same prompt when possible. ================================================ FILE: .claude/commands/icon.md ================================================ --- description: Generate an SVG icon from a design mockup using vectosolve vectorization allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Agent, AskUserQuestion, TodoWrite, mcp__vectosolve__vectorize --- # Icon - SVG Icon Generation from Design Mockup You generate production-quality SVG icons for Telegram Desktop by vectorizing design mockup screenshots using the vectosolve MCP service, then post-processing the result to match the Telegram icon format. **Arguments:** `$ARGUMENTS` = "$ARGUMENTS" If `$ARGUMENTS` is empty, ask the user to describe the icon they want and paste a cropped screenshot of it. ## Overview The workflow takes a cropped screenshot of an icon from a design mockup (grabbed from the clipboard), vectorizes it via the vectosolve MCP, then post-processes the SVG (recolor to white-on-transparent, restructure to minimal format, set 24x24 output size). Working directory: `.ai/icon_{name}/` with iterations labeled by letter (`a/`, `b/`, ...), each containing `source.png`. Output SVGs are in the icon root: `a.svg`, `b.svg`, etc. Follow-ups are supported: `/icon {icon_name} ` continues from where the previous run left off. ## Phase 0: Setup **Record the current time** (using `date` or equivalent) as `$START_TIME`. ### Step 0a: Clipboard grab (MUST be the VERY FIRST action) If there is an image attached to the user's message: 1. Generate a random 8-character hex string for `HASH` (use `openssl rand -hex 4` or similar). 2. **IMMEDIATELY** — before any other processing — run this Bash command to save the clipboard image: ```bash HASH=$(openssl rand -hex 4) && if [[ "$OSTYPE" == darwin* ]]; then bash .claude/grab_clipboard.sh ".ai/icon_${HASH}.png"; else powershell -ExecutionPolicy Bypass -File .claude/grab_clipboard.ps1 ".ai/icon_${HASH}.png"; fi ``` On macOS `.claude/grab_clipboard.sh` is used; on Windows `.claude/grab_clipboard.ps1`. Both grab the current clipboard image and save it to the specified path. 3. If the command fails (exit 1 / no image on clipboard): - Tell the user: **"Clipboard doesn't contain an image. Please copy the icon area first, then retry."** (On macOS: Cmd+Ctrl+Shift+4 to snip to clipboard; on Windows: Win+Shift+S.) - **STOP IMMEDIATELY. Do NOT continue.** You cannot use the image pasted in the conversation — it exists only as pixels in the chat, not as a file you can send to vectosolve. The clipboard grab is the ONLY way to get the image to disk. Do not attempt any workaround. 4. Read back the saved `.ai/icon_HASH.png` using the Read tool. 5. Compare it visually with the image pasted in the conversation. They should depict the same thing. - If they look **completely different**: delete `.ai/icon_HASH.png` and fail: > "The clipboard image doesn't match what you pasted. Please re-copy and retry." - If they look the same (or close enough): proceed. Store the temp path. If NO image is attached to the message, skip this step entirely. ### Step 0b: Fail-fast — verify vectosolve MCP Check that the `mcp__vectosolve__vectorize` tool is available by looking at your available tools list. If it is NOT available, fail immediately with: > vectosolve MCP is not configured. Set it up with: > ``` > claude mcp add vectosolve --scope user -e VECTOSOLVE_API_KEY=vs_xxx -- npx @vectosolve/mcp > ``` > Then restart Claude Code. ### Step 0c: Follow-up detection Extract the first word/token from `$ARGUMENTS` (everything before the first space or newline). Call it `FIRST_TOKEN`. Run these TWO commands using the Bash tool, **IN PARALLEL**: 1. `ls .ai/` — to see all existing icon project names 2. `ls .ai/icon_{FIRST_TOKEN}/context.md` — to check if this specific icon project exists **Evaluate the results:** - If command 2 **succeeds** (context.md exists): this is a **follow-up**. The icon name is `FIRST_TOKEN`. The follow-up description is everything in `$ARGUMENTS` after `FIRST_TOKEN`. - If command 2 **fails** (not found): this is a **new icon**. The full `$ARGUMENTS` is the icon description. ### Step 0d: New icon setup 1. Parse `$ARGUMENTS` to determine: - **Icon description**: what the icon should depict - **Icon type**: default is `menu` (24x24 menu/button icon). User may specify otherwise. - **Target subfolder**: `menu/` by default, or another subfolder if specified. 2. Choose an icon file name: - Lowercase letters and underscores only — **NO hyphens** - Match existing naming conventions (check `Telegram/Resources/icons/{subfolder}/`) - Must NOT conflict with existing icons - Must NOT collide with existing `.ai/icon_{name}/` directories 3. Create `.ai/icon_{name}/` and `.ai/icon_{name}/a/`. 4. Write `.ai/icon_{name}/context.md` with: ``` ## Icon: {icon_name} Type: {menu/other} Target: Telegram/Resources/icons/{subfolder}/{icon_name}.svg ## Original Request {full $ARGUMENTS text} ## Follow-ups (none yet) ``` 5. Set `LETTER` to `a`. ### Step 0e: Follow-up setup 1. Read `.ai/icon_{name}/context.md` to get the icon type, subfolder, and full history. 2. Find the latest existing letter folder in `.ai/icon_{name}/` (highest letter). 3. Set `LETTER` to the next letter after the latest. 4. Create `.ai/icon_{name}/{LETTER}/`. 5. Update `.ai/icon_{name}/context.md` — append the follow-up description to the `## Follow-ups` section: ``` ### Follow-up (starting at letter {LETTER}) {follow-up description} ``` ### Step 0f: Place source image If a clipboard image was grabbed in Step 0a: 1. Copy (or move) `.ai/icon_HASH.png` → `.ai/icon_{name}/source.png` (overwrite if exists — this is always the latest source). 2. Copy it to `.ai/icon_{name}/{LETTER}/source.png` (archive per-iteration source). 3. Delete the temp `.ai/icon_HASH.png` if it was copied (not moved). If NO image was grabbed: - **New icon with no image**: Ask the user to provide a screenshot. STOP. - **Follow-up with no image**: The existing `source.png` in the icon root carries forward. Copy it to `.ai/icon_{name}/{LETTER}/source.png`. If no source.png exists at all, ask the user for an image. ### Step 0g: Verify renderer Locate the render tool (`codegen_style` with `--render-svg` mode): ```bash if [[ "$OSTYPE" == darwin* ]]; then ls out/Debug/codegen_style else ls out/Telegram/codegen/codegen/style/Debug/codegen_style.exe fi ``` If missing, build it: `cmake --build out --config Debug --target codegen_style` Test on a known good SVG (use the appropriate binary path for the OS): ```bash CODEGEN=$(if [[ "$OSTYPE" == darwin* ]]; then echo out/Debug/codegen_style; else echo out/Telegram/codegen/codegen/style/Debug/codegen_style.exe; fi) $CODEGEN --render-svg Telegram/Resources/icons/menu/tag_add.svg .ai/icon_{name}/test_render.png 512 ``` If works → delete test render, set `RENDER_AVAILABLE = true`. If fails → `RENDER_AVAILABLE = false`. ## Phase 1: Vectorize & Post-process ### Step 1a: Call vectosolve Use the `mcp__vectosolve__vectorize` tool with `file_path` set to the **absolute path** of `.ai/icon_{name}/{LETTER}/source.png`. **If this fails, STOP IMMEDIATELY.** Do NOT try to generate the SVG manually or by any other means. Report the error to the user and let them fix the issue (bad API key, no credits, network error, etc.). Save the returned SVG content to `.ai/icon_{name}/{LETTER}/raw_vectosolve.svg`. The MCP tool calls the vectosolve API ($0.20/call). The API key is stored in `~/.claude.json` MCP config (never in the repository). ### Step 1b: Post-process the SVG The vectosolve SVG will have colors from the mockup, arbitrary dimensions, and possibly a non-square aspect ratio from a non-square screenshot crop. Post-processing fixes this by adjusting the **viewBox** — leave path coordinates untouched. **Do NOT transform path coordinates.** Vectosolve's paths are correct — the only thing wrong is the framing. All geometry adjustments are done by manipulating the `viewBox` and the `width`/`height` attributes. #### Sub-step 1: Read the request and determine parameters Before touching the SVG, determine these from the user's request and context.md: 1. **Output size** (`OUT_W × OUT_H`): default is `24px × 24px` for menu icons. The user may request different dimensions (e.g., 36×36, 48×48, or non-square). Always check the request. 2. **Content padding**: default is ~2px equivalent on each side at the output scale (so content fills roughly (OUT_W-4) × (OUT_H-4)). The user may request different padding or edge-to-edge. 3. **Centering**: default is centered both horizontally and vertically. The user may request specific alignment (e.g., "align to bottom"). #### Sub-step 2: Parse the raw SVG 1. Extract the `viewBox`: `viewBox="VB_X VB_Y VB_W VB_H"` (typically `0 0 W H`). 2. Identify ALL paths. Classify each: - **Background**: a rect or path spanning the full viewBox (first path that's a simple rectangle matching the viewBox bounds). **Remove it entirely.** - **Content**: the actual icon shapes. **Keep these, paths unchanged.** 3. If paths have `transform="translate(TX,TY)"` attributes, that's fine — keep them as-is. The viewBox framing will work regardless. #### Sub-step 3: Compute the content bounding box Estimate the bounding box of the content paths (after removing the background). You can either: - Eyeball it from the path coordinates (look at first/last M commands and extremes of curves) - Or for precision, write a quick script to parse the paths and find min/max X/Y Call the result: `CX_MIN, CY_MIN, CX_MAX, CY_MAX`. Content dimensions: `CW = CX_MAX - CX_MIN`, `CH = CY_MAX - CY_MIN`. #### Sub-step 4: Compute the new viewBox The viewBox determines what part of the SVG coordinate space maps to the output rectangle. By expanding the viewBox beyond the content bounds, we add padding. By making the viewBox aspect ratio match the output aspect ratio, we prevent stretching. 1. **Output aspect ratio**: `OUT_AR = OUT_W / OUT_H` (for 24×24 this is 1.0). 2. **Padding in SVG coordinates**: we want ~2px padding at output scale. The scale factor is `OUT_W / VB_CONTENT_W` approximately, so padding in SVG coords = `2 * (CW / (OUT_W - 4))` (or similar — the exact formula depends on which dimension is dominant). Simpler approach: aim for content to occupy ~83% of the viewBox (≈ 20/24), so: - `PADDED_W = CW / 0.83` - `PADDED_H = CH / 0.83` 3. **Match output aspect ratio**: the viewBox aspect ratio must equal `OUT_AR` to avoid stretching. - If `PADDED_W / PADDED_H > OUT_AR`: width is dominant → `VB_W = PADDED_W`, `VB_H = VB_W / OUT_AR` - If `PADDED_W / PADDED_H < OUT_AR`: height is dominant → `VB_H = PADDED_H`, `VB_W = VB_H * OUT_AR` - If equal: `VB_W = PADDED_W`, `VB_H = PADDED_H` 4. **Center the content** in the new viewBox: - `VB_X = CX_MIN - (VB_W - CW) / 2` - `VB_Y = CY_MIN - (VB_H - CH) / 2` - (Adjust if the user requested non-centered alignment) The new viewBox is: `viewBox="VB_X VB_Y VB_W VB_H"`. #### Sub-step 5: Recolor to white-on-transparent - Replace ALL `fill` color values (anything that isn't `none`) with `#FFFFFF`. - Remove ALL `stroke` and `stroke-width` attributes entirely. - Remove `opacity` attributes if present. #### Sub-step 6: Determine path composition Look at the icon's visual structure and decide how paths should combine: - **Outlined shape** (e.g., circle outline with something inside): combine outer + inner cutout into one `` with `fill-rule="evenodd"`. - **Separate distinct parts** (e.g., magnifying glass + checkmark): keep as separate `` elements. - **Filled shape with cutout** (e.g., filled circle with checkmark punched out): combine into one path with `fill-rule="evenodd"`. #### Sub-step 7: Assemble final SVG ```xml ``` - `width`/`height` = the output size from the request (default `24px`/`24px`). - `viewBox` = the computed viewBox from Sub-step 4. The SVG renderer maps this coordinate region to the output size. - Path `d` attributes are **unchanged** from vectosolve output (just background removed, colors replaced). - No ``, `id`, `xmlns:xlink`, `version`, `class`, `style`, XML comments, `<metadata>`, or `preserveAspectRatio`. - No `<circle>`, `<rect>`, `<line>` — only `<path>`. Write the final SVG to `.ai/icon_{name}/{LETTER}.svg`. ### Step 1c: Render If `RENDER_AVAILABLE`: ```bash $CODEGEN --render-svg ".ai/icon_{name}/{LETTER}.svg" ".ai/icon_{name}/render_{LETTER}.png" 512 ``` Read the render to visually verify the result. ## Phase 2: Review After rendering, assess the result: 1. **Recognizable?** The icon should be clearly identifiable as the intended symbol. 2. **Scale reasonable?** Should fill the space appropriately with ~2-3px padding. 3. **Clean lines?** No broken paths, artifacts, or unwanted elements. 4. **Correct colors?** All white on transparent (no leftover colors from the mockup). If the result looks good → proceed to Phase 3 (Output). If there are fixable issues (stray element, missed color, etc.) → fix the SVG directly, re-render, and re-check. If the result is poor (vectosolve couldn't handle the input well) → report to the user and suggest: - Trying a cleaner/larger crop of the icon - Providing a different screenshot - Following up: `/icon {icon_name} <description of what to change>` ## Phase 3: Output 1. Read the `Target:` line from `.ai/icon_{name}/context.md` to get the output path. 2. Copy the final SVG to that target path (e.g., `Telegram/Resources/icons/menu/{icon_name}.svg`). 3. Update `.ai/icon_{name}/context.md` — append to the end: ``` ## Latest Output Letter: {LETTER} Written to: {target_path} ``` 4. Report to the user: - Final icon file path - Number of vectosolve calls made (cost at $0.20/call) - Suggest verifying visually - Working directory `.ai/icon_{name}/` has all iterations - Elapsed time since `$START_TIME` (format `Xm Ys`) - Follow-up: `/icon {icon_name} <description of what to change>` ## Text-only Follow-ups (no new image) When a follow-up has no attached image, the user wants to refine the existing SVG based on text feedback. In this case: 1. Skip Phase 1 (no vectosolve call needed). 2. Read the latest SVG (`.ai/icon_{name}/{prev_letter}.svg`). 3. Read the latest render if available. 4. Apply the user's requested changes by editing the SVG directly. 5. Save as `.ai/icon_{name}/{LETTER}.svg`. 6. Render, review, and output as normal (Phases 1c → 3). If the changes are too complex for manual SVG editing, suggest the user provide a new screenshot instead. ## Error Handling - If clipboard grab fails → tell user to re-copy and retry. - If vectosolve returns an error → report it and suggest a different/cleaner screenshot. - If vectosolve returns SVG that can't be parsed → save raw output for debugging, report to user. - If the render helper fails → set `RENDER_AVAILABLE = false`, continue with SVG-only review. - If post-processing produces a broken SVG → fall back to the raw vectosolve output and do lighter cleanup. ================================================ FILE: .claude/commands/planner.md ================================================ --- description: Plan and create a repetitive task automation (prompt.md + tasks.json pair) allowed-tools: Read, Write, Edit, Glob, Grep, Bash(mkdir:*), Bash(ls:*), AskUserQuestion --- # Task Planner - Create Automated Task Workflows You are setting up a new **repetitive task automation** for Claude Code. The goal is to create a folder in `.ai/<featurename>/` containing: - `prompt.md` - Detailed instructions for the autonomous agent - `tasks.json` - List of tasks with completion tracking This pair can then be executed via `.claude/iterate.ps1 <featurename>`. ## Your Workflow ### 1. Understand the Goal First, understand what the user wants to automate. Ask clarifying questions using AskUserQuestion if needed: - What is the overall goal/feature being implemented? - What are the individual tasks involved? - Are there dependencies between tasks? - What files/areas of the codebase are involved? - Are there any reference examples or patterns to follow? ### 2. Choose a Feature Name The `<featurename>` should be: - Short (1-2 words, lowercase, hyphen-separated) - Easy to type on command line - Descriptive of the work being done - Not already used in `.ai/` Check existing folders: ```bash ls .ai/ ``` Suggest a name to the user or let them specify one directly via $ARGUMENTS. ### 3. Create the Folder and Files Create `.ai/<featurename>/`: **prompt.md** should include: - Overview of what we're doing - Architecture/context needed - Step-by-step instructions for each task type - Code patterns and examples - Build/test commands - Commit message format (see below) ### Commit Message Guidelines All prompts should specify commit message length requirements: - **Soft limit**: ~50 characters (ideal length for first line) - **Hard limit**: 76 characters (must not exceed) Example instruction for prompt.md: ``` ## Commit Format First line: Short summary ending with a dot (aim for ~50 chars, max 76 chars) <Optional body with details, also ending with a dot.> IMPORTANT: Never try to commit files in .ai/ ``` **tasks.json** format: ```json { "tasks": [ { "id": "task-id", "title": "Short task title", "description": "Detailed description of what to do", "started": false, "completed": false, "dependencies": ["other-task-id"] } ] } ``` ### 4. Iterate with the User After creating initial files, the user may want to: - Add more tasks to tasks.json - Refine the prompt with more details - Add examples or patterns - Clarify instructions Keep refining until the user is satisfied. ## Arguments If `$ARGUMENTS` is provided, it's the feature name to use: - `$ARGUMENTS` = "$ARGUMENTS" If empty, you'll need to determine/suggest a name based on the discussion. ## Examples ### Example 1: Settings Migration ``` /taskplanner settings-upgrade ``` Creates `.ai/settings-upgrade/` with prompt and tasks for migrating settings sections. ### Example 2: Open-ended ``` /taskplanner ``` Starts a conversation to understand what needs to be automated, then creates the appropriate folder. ## Starting Point Let's begin! Please describe: 1. What repetitive coding task do you want to automate? 2. What is the end goal? 3. Do you have initial tasks in mind, or should we discover them together? ================================================ FILE: .claude/commands/reflect.md ================================================ --- description: Learn from corrections — examine staged vs unstaged diffs and optionally distill insights into AGENTS.md or REVIEW.md allowed-tools: Read, Edit, Bash(git diff:*), Bash(git status:*), Bash(git log:*), Bash(ls:*), AskUserQuestion --- # Reflect — Learn from Corrections You are a reflection agent. Your job is to examine the difference between what an AI agent produced (staged changes) and what the user corrected (unstaged changes), and determine whether any **general, reusable insight** can be extracted and added to the project's coding guidelines. **CRITICAL: Use extended thinking ultrathink for your analysis. This requires deep, careful reasoning.** ## Arguments `$ARGUMENTS` = "$ARGUMENTS" If `$ARGUMENTS` is provided, it is a task name (project name from the `/task` workflow). This means the agent was working within `.ai/<task-name>/` and you should read the task context for deeper understanding of what the agent was trying to do. If `$ARGUMENTS` is empty, skip the task context step — just work from the diffs alone. ## Context The workflow is: 1. An AI agent implemented something and its changes were staged (`git add`). 2. The user reviewed and corrected the agent's work. These corrections are unstaged. 3. You are now invoked to reflect on what went wrong and whether it reveals a pattern. ## Step 1: Gather the Diffs and Task Context Run these commands in parallel: ```bash git diff --cached # What the agent wrote (staged) git diff # What the user corrected (unstaged, on top of staged) git status # Which files are involved ``` If either diff is empty, tell the user and stop. Both diffs must be non-empty for reflection to be meaningful. ### Task context (only if `$ARGUMENTS` is non-empty) The task name is `$ARGUMENTS`. Read the task's project context: 1. Read `.ai/$ARGUMENTS/about.md` — the project-level description of what this feature does. 2. Find the latest task iteration folder: list `.ai/$ARGUMENTS/` and pick the folder with the highest letter (`a`, `b`, `c`, ...). 3. Read `.ai/$ARGUMENTS/<latest-letter>/context.md` — the detailed implementation context the agent was working from. This helps you distinguish between: - **Task-specific mistakes** — the agent misunderstood this particular feature's requirements or made a wrong choice within the specific problem. These are NOT documentation-worthy. - **General convention mistakes** — the agent did something that violates a pattern the codebase follows broadly, regardless of which feature is being implemented. These ARE potentially documentation-worthy. Having the task context makes this distinction much sharper. Without it, you might mistake a task-specific correction for a general pattern or vice versa. ## Step 2: Read the Current Guidelines Read both files: - `AGENTS.md` — development guidelines: build system, coding style, API usage patterns, UI styling, localization, rpl, architectural conventions, "how to do things" - `REVIEW.md` — mechanical style and formatting rules: brace placement, operator position, type checks, variable initialization, call formatting Read them carefully. You need to know exactly what's already documented to avoid duplicates and detect contradictions. ## Step 3: Analyze the Corrections Now think deeply. For each correction the user made, ask yourself: 1. **What did the agent do wrong?** Understand the specific mistake. 2. **Why was it wrong?** Identify the underlying principle. 3. **Is this already covered by AGENTS.md or REVIEW.md?** Check carefully: - If the existing rule's scope, title, and examples **clearly cover** this exact scenario and the agent just ignored it — that's not a documentation problem. Skip it. - If the existing rule **technically applies** but its scope is too narrow, its examples don't illustrate this usage pattern, or its wording would reasonably lead an agent to think it doesn't apply here — **the rule needs improvement**. Treat this as a potential insight (broaden the scope, add examples, adjust wording). A rule that agents repeatedly violate is an ineffective rule. 4. **Is this specific to this particular task, or is it general?** Most corrections are task-specific ("wrong variable here", "this should call that function instead"). These are NOT documentation-worthy. Only patterns that would apply across many different tasks are worth capturing. 5. **Would documenting this actually help a future agent?** Some things are too context-dependent or too obvious to be useful as a written rule. Be honest about this. ## Step 4: Decision After analysis, you MUST reach one of these conclusions: ### Conclusion A: No actionable insight The corrections are purely task-specific, or the existing documentation clearly and specifically covers the exact scenario and the agent simply ignored it. Say what the corrections were and why no doc changes are needed. Then **stop**. ### Conclusion B: New insight found You can articulate a **concise, general rule** that: - Applies broadly (not just to this one task) - Is not already documented - Would genuinely help a future agent avoid the same class of mistake - Can be expressed in a few sentences with a clear code example If you have a new insight, proceed to Step 5. ### Conclusion C: Existing rule needs improvement A rule already exists in AGENTS.md or REVIEW.md, but its **scope is too narrow**, its **examples don't cover** the pattern the agent encountered, or its **wording** would reasonably lead an agent to think the rule doesn't apply. The agent's mistake is evidence the rule isn't effective. This is NOT the same as Conclusion A. The test: would a careful agent, reading the existing rule, clearly know it applies to this specific situation? If no — the rule needs to be broadened, its examples expanded, or its title/scope adjusted. Proceed to Step 5. **Common signs of an ineffective rule:** - The rule's title or scope restricts it to a context narrower than the actual principle (e.g., "in localization calls" when the pattern applies generally) - The examples only show one usage pattern, and the agent encountered a different one - The wording describes *what* to use but not *when* — so agents only apply it in situations that look like the examples ## Step 5: Categorize and Check for Contradictions ### Where does it belong? - **REVIEW.md** — if it's a mechanical/style rule: formatting, naming, syntax preferences, call structure, brace/operator placement, type usage patterns. Rules that can be checked by looking at code locally without understanding the broader feature. - **AGENTS.md** — if it's an architectural/behavioral guideline: how to use APIs, where to place code, design patterns, build conventions, module organization, reactive patterns (rpl), localization usage, style system usage. Rules that require understanding the broader context. ### Does it contradict existing content? Read the target file again carefully. Check if: 1. The new insight **contradicts** an existing rule — if so, do NOT just append or just remove. Instead, use AskUserQuestion to present both the existing rule and the new insight to the user, explain the contradiction, and ask how to reconcile them. 2. The new insight **overlaps** with an existing rule — if so, consider whether the existing rule should be extended/refined rather than adding a separate entry. 3. The new insight is **complementary** — it adds something new without conflicting. This is the simplest case. ## Step 6: Propose the Change **Do NOT silently edit the files.** First, present your proposed change to the user: - Quote the exact text you want to add or modify - Explain which file and where in the file - Explain why this is general enough to document - If modifying existing text, show the before and after Use AskUserQuestion to get the user's approval before making any edit. Only after the user approves, apply the edit using the Edit tool. ## Rules - **Keep docs lean and high-signal.** Don't add vague or overly specific rules. But don't default to inaction either — if the user had to manually fix something that a better-worded rule would have prevented, improving that rule is high-signal work. - **Never dump corrections verbatim.** The goal is distilled principles, not a changelog of mistakes. - **One insight per reflection, maximum.** If you think you see multiple insights, pick the strongest one. You can always run `/reflect` again next time. - **Keep the same style.** Match the formatting, tone, and level of detail of the target file. REVIEW.md uses specific before/after code examples. AGENTS.md uses explanatory sections with code snippets. - **Don't add "don't do X" rules.** Frame rules positively: "do Y" is better than "don't do X." Show the right way, not just the wrong way. - **No meta-commentary.** Don't add notes like "Added after reflection on..." — the rule should read as if it was always there. ================================================ FILE: .claude/commands/release.md ================================================ --- description: Prepare changelog, set version, and commit a new release allowed-tools: Read, Bash, Edit, Grep, AskUserQuestion --- # Release — Changelog, Set Version, Commit Full release flow: generate changelog entry, run `set_version`, and commit. **Arguments:** `$ARGUMENTS` = "$ARGUMENTS" Parse `$ARGUMENTS` for two optional parts (in any order): - A **version number** like `6.7` or `6.7.0` — if provided, use it as the new version exactly. - The word **"beta"** — if present, mark the release as beta. If no version number is given, auto-increment the patch component (see step 2). ## Steps ### 1. Check git status is clean Run `git status --porcelain`. If there are any uncommitted changes, **stop** and ask the user to commit or discard them before proceeding. Do not continue until status is clean. ### 2. Read the current changelog Read `changelog.txt` from the repository root. Note the **latest version number** on the first line (e.g. `6.6.3 beta (12.03.26)`). Parse its major.minor.patch components. ### 3. Determine the new version number - **If a version was provided in arguments**, use it directly (append `.0` if only major.minor was given). - **If no version was provided**, auto-increment from the latest changelog version: - If it was a beta, and the new release is **not** beta, reuse the same version number but drop "beta". - If the new release is beta and the latest was also beta with the same major.minor, bump patch. - Otherwise bump the patch component by 1. - Present the chosen version to the user and ask for confirmation before proceeding. If the user suggests a different version, use that instead. ### 4. Fetch tags and determine the last release tag Run `git fetch origin --tags` first to ensure all tags from the public repository are available locally. Then run `git tag --sort=-v:refname` and find the most recent `v*` tag. This is the baseline for the diff. ### 5. Collect commits Run `git log <last-tag>..HEAD --oneline` to get all commits since the last release. ### 6. Write the changelog entry Analyze every commit message. Group them mentally into features, improvements, and bug fixes. Then produce **brief, user-facing bullet points** following these rules: - **Style:** Match the existing changelog tone exactly — short, imperative sentences starting with a verb (Fix, Add, Allow, Show, Improve, Support…). Keep the trailing periods (the existing changelog uses them). - **Brevity:** Each bullet should be one short sentence, around 80 characters when possible. No implementation details. No commit hashes. - **Selection:** Only include changes that matter to end users. Skip CI, build infra, submodule bumps, code style, refactors, and intermediate WIP commits. Collapse many related commits (e.g. a dozen image-editor commits) into one or two bullets. - **Ordering:** Features first, then improvements, then bug fixes. - **Quantity:** Aim for 4-12 bullets total depending on the amount of changes. ### 7. Format and insert into changelog.txt Use this exact format (date is today in DD.MM.YY): ``` <version> [beta ](DD.MM.YY) - Bullet one. - Bullet two. ``` Prepend the new entry at the very top of `changelog.txt`, separated by a blank line from the previous first entry. Use the Edit tool. ### 8. Wait for approval After writing the entry to `changelog.txt` (step 7), tell the user the changelog has been updated and ask them to review it in the IDE. They can edit it directly and tell you to continue, or tell you what to change in chat. Do **not** print the full entry in chat — the file itself is the review surface. **Do NOT proceed until the user explicitly approves.** ### 9. Run set_version Once approved, run the `set_version` script from the repository root. On Windows: ``` .\Telegram\build\set_version.bat <version_arg> ``` Where `<version_arg>` is formatted as the `set_version` script expects: - Stable: `6.7.0` or `6.7` - Beta: `6.7.0.beta` Verify the script exits successfully (exit code 0). If it fails, show the error and stop. ### 10. Commit Stage all changes and create a commit. The commit message format: **First line:** - For stable: `Version <major>.<minor>.` if patch is 0, otherwise `Version <major>.<minor>.<patch>.` - For beta: `Beta version <major>.<minor>.<patch>.` **Then an empty line, then the changelog bullets.** Copy bullet lines from the changelog as-is. Only wrap lines that exceed 72 characters; shorter lines must stay on a single line. When wrapping is needed, break at logically correct places (between words/phrases) and indent continuation lines with two spaces. Example commit message: ``` Beta version 6.6.3. - Drawing tools in image editor (brush, marker, eraser, arrow). - Draw-to-reply button in media viewer. - Trim recorded voice messages. - Fix reorder freeze in chats list. ``` Use a HEREDOC to pass the message to `git commit -a`. ### 11. Done Run `git log -1` to show the resulting commit and confirm success. ================================================ FILE: .claude/commands/task.md ================================================ --- description: Implement a feature or fix using multi-agent workflow with fresh context at each phase allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Task, AskUserQuestion, TodoWrite --- # Task - Multi-Agent Implementation Workflow You orchestrate a multi-phase implementation workflow that uses fresh agent spawns to work within context window limits on a large codebase. **Arguments:** `$ARGUMENTS` = "$ARGUMENTS" If `$ARGUMENTS` is provided, it's the task description. If empty, ask the user what they want implemented. ## Overview The workflow is organized around **projects**. Each project lives in `.ai/<project-name>/` and can contain multiple sequential **tasks** (labeled `a`, `b`, `c`, ... `z`). Project structure: ``` .ai/<project-name>/ about.md # Single source of truth for the entire project a/ # First task context.md # Gathered codebase context for this task plan.md # Implementation plan review1.md # Code review documents (up to 3) review2.md review3.md b/ # Follow-up task context.md plan.md review1.md c/ # Another follow-up task ... ``` - `about.md` is the project-level blueprint — a single comprehensive document describing what this project does and how it works, written as if everything is already fully implemented. It contains no temporal state ("current state", "pending changes", "not yet implemented"). It is **rewritten** (not appended to) each time a new task starts, incorporating the new task's changes as if they were always part of the design. - Each task folder (`a/`, `b/`, ...) contains self-contained files for that task. The task's `context.md` carries all task-specific information: what specifically needs to change, the delta from the current codebase, gathered file references and code patterns. Planning, implementation, and review agents only read the current task's folder. ## Phase 0: Setup **Record the current time now** (using `Get-Date` in PowerShell or equivalent) and store it as `$START_TIME`. You will use this at the end to display total elapsed time. ⚠️ **CRITICAL: Follow-up detection MUST happen FIRST, before anything else.** ### Step 0a: Follow-up detection (MANDATORY — do this BEFORE understanding the task) Extract the first word/token from `$ARGUMENTS` (everything before the first space or newline). Call it `FIRST_TOKEN`. Then run these TWO commands using the Bash tool, IN PARALLEL, right now: 1. `ls .ai/` — to see all existing project names 2. `ls .ai/<FIRST_TOKEN>/about.md` — to check if this specific project exists **Evaluate the results:** - If command 2 **succeeds** (the file exists): this is a **follow-up task**. The project name is `FIRST_TOKEN`. The task description is everything in `$ARGUMENTS` AFTER `FIRST_TOKEN` (strip leading whitespace). - If command 2 **fails** (file not found): this is a **new project**. The full `$ARGUMENTS` is the task description. **Do NOT proceed to step 0b until you have run these commands and determined follow-up vs new.** ### Step 0b: Project setup **For new projects:** - Using the list from command 1, pick a unique short name (1-2 lowercase words, hyphen-separated) that doesn't collide with existing projects. - Create `.ai/<project-name>/` and `.ai/<project-name>/a/`. - Set current task letter = `a`. **For follow-up tasks:** - Scan `.ai/<project-name>/` for existing task folders (`a/`, `b/`, ...). Find the latest one (highest letter). - The previous task letter = that highest letter. - The new task letter = next letter in sequence. - Create `.ai/<project-name>/<new-letter>/`. Then proceed to Phase 1 (Context Gathering) in both cases. Follow-up tasks do NOT skip context gathering — they go through a modified version of it. ## Phase 1: Context Gathering ### For New Projects (task letter = `a`) Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure: ``` You are a context-gathering agent for a large C++ codebase (Telegram Desktop). TASK: <paste the user's task description here> YOUR JOB: Read AGENTS.md, inspect the codebase, find ALL files and code relevant to this task, and write two documents. Steps: 1. Read AGENTS.md for project conventions and build instructions. 2. Search the codebase for files, classes, functions, and patterns related to the task. 3. Read all potentially relevant files. Be thorough - read more rather than less. 4. For each relevant file, note: - File path - Relevant line ranges - What the code does and how it relates to the task - Key data structures, function signatures, patterns used 5. Look for similar existing features that could serve as a reference implementation. 6. Check api.tl if the task involves Telegram API. 7. Check .style files if the task involves UI. 8. Check lang.strings if the task involves user-visible text. Write TWO files: ### File 1: .ai/<project-name>/about.md NOTE: This file is NOT used by any agent in the current task. It exists solely as a starting point for a FUTURE follow-up task's context gatherer. No planning, implementation, or review agent will ever read it. Only the context-gathering agent of the next follow-up task reads about.md (together with the latest context.md) to produce a fresh context.md for that next task. Write it as if the project is already fully implemented and working. It should contain: - **Project**: What this project does (feature description, goals, scope) - **Architecture**: High-level architectural decisions, which modules are involved, how they interact - **Key Design Decisions**: Important choices made about the approach - **Relevant Codebase Areas**: Which parts of the codebase this project touches, key types and APIs involved Do NOT include temporal state like "Current State", "Pending Changes", "Not yet implemented", "TODO", or any other framing that distinguishes between "done" and "not done". Describe the project as a complete, coherent whole — as if everything is already working. This is a project overview, not a status tracker. Task-specific work belongs exclusively in context.md. ### File 2: .ai/<project-name>/a/context.md This is the task-specific implementation context. This is the PRIMARY document — all downstream agents (planning, implementation, review) will read ONLY this file. It must be completely self-contained. It should contain: - **Task Description**: The full task restated clearly - **Relevant Files**: Every file path with line ranges and descriptions of what's there - **Key Code Patterns**: How similar things are done in the codebase (with code snippets) - **Data Structures**: Relevant types, structs, classes - **API Methods**: Any TL schema methods involved (copied from api.tl) - **UI Styles**: Any relevant style definitions - **Localization**: Any relevant string keys - **Build Info**: Build command and any special notes - **Reference Implementations**: Similar features that can serve as templates Be extremely thorough. Another agent with NO prior context will read this file and must be able to understand everything needed to implement the task. ``` After this agent completes, read both `about.md` and `a/context.md` to verify they were written properly. ### For Follow-up Tasks (task letter = `b`, `c`, ...) Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure: ``` You are a context-gathering agent for a follow-up task on an existing project in a large C++ codebase (Telegram Desktop). NEW TASK: <paste the follow-up task description here> YOUR JOB: Read the existing project state, gather any additional context needed, and produce fresh documents for the new task. Steps: 1. Read AGENTS.md for project conventions and build instructions. 2. Read .ai/<project-name>/about.md — this is the project-level blueprint describing everything done so far. 3. Read .ai/<project-name>/<previous-letter>/context.md — this is the previous task's gathered context. 4. Understand what has already been implemented by reading the actual source files referenced in about.md and the previous context. 5. Based on the NEW TASK description, search the codebase for any ADDITIONAL files, classes, functions, and patterns that are relevant to the new task but not already covered. 6. Read all newly relevant files thoroughly. Write TWO files: ### File 1: .ai/<project-name>/about.md (REWRITE) NOTE: This file is NOT used by any agent in the current task. It exists solely as a starting point for a FUTURE follow-up task's context gatherer. No planning, implementation, or review agent will ever read it. You are rewriting it now so that the next follow-up has an accurate project overview to start from. REWRITE this file (not append). The new about.md must be a single coherent document that describes the project as if everything — including this new task's changes — is already fully implemented and working. It should incorporate: - Everything from the old about.md that is still accurate and relevant - The new task's functionality described as part of the project (not as "changes to make") - Any changed design decisions or architectural updates from the new task requirements It should NOT contain: - Any temporal state: "Current State", "Pending Changes", "TODO", "Not yet implemented" - History of how requirements changed between tasks - References to "the old approach" vs "the new approach" - Task-by-task changelog or timeline - Any distinction between "what was done before" and "what this task adds" - Information that contradicts the new task requirements (if the new task changes direction, the about.md should reflect the NEW direction as if it was always the plan) Think of about.md as "the complete description of what this project does and how it works." Someone reading it should understand the full project as a finished product, without knowing it went through multiple tasks. ### File 2: .ai/<project-name>/<new-letter>/context.md This is the PRIMARY document — all downstream agents (planning, implementation, review) will read ONLY this file. It must be completely self-contained. about.md will NOT be available to them. It should contain: - **Task Description**: The new task restated clearly, with enough project background (from about.md and previous context.md) that an implementation agent can understand it without reading any other .ai/ files - **Relevant Files**: Every file path with line ranges relevant to THIS task (including files modified by previous tasks and any newly relevant files) - **Key Code Patterns**: How similar things are done in the codebase - **Data Structures**: Relevant types, structs, classes - **API Methods**: Any TL schema methods involved - **UI Styles**: Any relevant style definitions - **Localization**: Any relevant string keys - **Build Info**: Build command and any special notes - **Reference Implementations**: Similar features that can serve as templates Be extremely thorough. Another agent with NO prior context will read ONLY this file and must be able to understand everything needed to implement the new task. Do NOT assume the reader has seen about.md or any previous task files. The context.md is the single source of truth for all downstream agents — it must include all relevant project background, not just the delta. ``` After this agent completes, read both `about.md` and `<new-letter>/context.md` to verify they were written properly. ## Phase 2: Planning Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure: ``` You are a planning agent. You must create a detailed implementation plan. Read these files: - .ai/<project-name>/<letter>/context.md - Contains all gathered context for this task - Then read the specific source files referenced in context.md to understand the code deeply. Think carefully about the implementation approach. Create a detailed plan in: .ai/<project-name>/<letter>/plan.md The plan.md should contain: ## Task <one-line summary> ## Approach <high-level description of the implementation approach> ## Files to Modify <list of files that will be created or modified> ## Files to Create <list of new files, if any> ## Implementation Steps Each step must be specific enough that an agent can execute it without ambiguity: - Exact file paths - Exact function names - What code to add/modify/remove - Where exactly in the file (after which function, in which class, etc.) Number every step. Group steps into phases if there are more than ~8 steps. ### Phase 1: <name> 1. <specific step> 2. <specific step> ... ### Phase 2: <name> (if needed) ... ## Build Verification - Build command to run - Expected outcome ## Status - [ ] Phase 1: <name> - [ ] Phase 2: <name> (if applicable) - [ ] Build verification - [ ] Code review ``` After this agent completes, read `plan.md` to verify it was written properly. ## Phase 3: Plan Assessment Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure: ``` You are a plan assessment agent. Review and refine an implementation plan. Read these files: - .ai/<project-name>/<letter>/context.md - .ai/<project-name>/<letter>/plan.md - Then read the actual source files referenced to verify the plan makes sense. Carefully assess the plan: 1. **Correctness**: Are the file paths and line references accurate? Does the plan reference real functions and types? 2. **Completeness**: Are there missing steps? Edge cases not handled? 3. **Code quality**: Will the plan minimize code duplication? Does it follow existing codebase patterns from AGENTS.md? 4. **Design**: Could the approach be improved? Are there better patterns already used in the codebase? 5. **Phase sizing**: Each phase should be implementable by a single agent in one session. If a phase has more than ~8-10 substantive code changes, split it further. Update plan.md with your refinements. Keep the same structure but: - Fix any inaccuracies - Add missing steps - Improve the approach if you found better patterns - Ensure phases are properly sized for single-agent execution - Add a line at the top of the Status section: `Phases: <N>` indicating how many implementation phases there are - Add `Assessed: yes` at the bottom of the file If the plan is small enough for a single agent (roughly <=8 steps), mark it as a single phase. ``` After this agent completes, read `plan.md` to verify it was assessed. ## Phase 4: Implementation Now read `plan.md` yourself to understand the phases. For each phase in the plan that is not yet marked as done, spawn an implementation agent (Task tool, subagent_type=`general-purpose`): ``` You are an implementation agent working on phase <N> of an implementation plan. Read these files first: - .ai/<project-name>/<letter>/context.md - Full codebase context - .ai/<project-name>/<letter>/plan.md - Implementation plan Then read the source files you'll be modifying. YOUR TASK: Implement ONLY Phase <N> from the plan: <paste the specific phase steps here> Rules: - Follow the plan precisely - Follow AGENTS.md coding conventions (no comments except complex algorithms, use auto, empty line before closing brace, etc.) - Do NOT modify .ai/ files except to update the Status section in plan.md - When done, update plan.md Status section: change `- [ ] Phase <N>: ...` to `- [x] Phase <N>: ...` - Do NOT work on other phases When finished, report what you did and any issues encountered. ``` After each implementation agent returns: 1. Read `plan.md` to check the status was updated. 2. If more phases remain, spawn the next implementation agent. 3. If all phases are done, proceed to build verification. ## Phase 5: Build Verification Only run this phase if the task involved modifying project source code (not just docs or config). Spawn a build verification agent (Task tool, subagent_type=`general-purpose`): ``` You are a build verification agent. Read these files: - .ai/<project-name>/<letter>/context.md - .ai/<project-name>/<letter>/plan.md The implementation is complete. Your job is to build the project and fix any build errors. Steps: 1. Run (from repository root): cmake --build ./out --config Debug --target Telegram 2. If the build succeeds, update plan.md: change `- [ ] Build verification` to `- [x] Build verification` 3. If the build fails: a. Read the error messages carefully b. Read the relevant source files c. Fix the errors in accordance with the plan and AGENTS.md conventions d. Rebuild and repeat until the build passes e. Update plan.md status when done Rules: - Only fix build errors, do not refactor or improve code - Follow AGENTS.md conventions - If build fails with file-locked errors (C1041, LNK1104), STOP and report - do not retry When finished, report the build result. ``` After the build agent returns, read `plan.md` to confirm the final status. Then proceed to Phase 6. ## Phase 6: Code Review Loop After build verification passes, run up to 3 review-fix iterations to improve code quality. Set iteration counter `R = 1`. ### Review Loop ``` LOOP: 1. Spawn review agent (Step 6a) with iteration R 2. Read review<R>.md verdict: - "APPROVED" → go to FINISH - Has improvement suggestions → spawn fix agent (Step 6b) 3. After fix agent completes and build passes: R = R + 1 If R > 3 → go to FINISH (stop iterating, accept current state) Otherwise → go to step 1 FINISH: - Update plan.md: change `- [ ] Code review` to `- [x] Code review` - Proceed to Completion ``` ### Step 6a: Code Review Agent Spawn an agent (Task tool, subagent_type=`general-purpose`): ``` You are a code review agent for Telegram Desktop (C++ / Qt). Read these files: - .ai/<project-name>/<letter>/context.md - Codebase context - .ai/<project-name>/<letter>/plan.md - Implementation plan - REVIEW.md - Style and formatting rules to enforce <if R > 1, also read:> - .ai/<project-name>/<letter>/review<R-1>.md - Previous review (to see what was already addressed) Then run `git diff` to see all uncommitted changes made by the implementation. Implementation agents do not commit, so `git diff` shows exactly the current feature's changes. Then read the modified source files in full to understand changes in context. Perform a thorough code review. REVIEW CRITERIA (in order of importance): 1. **Correctness and safety**: Obvious logic errors, missing null checks at API boundaries, potential crashes, use-after-free, dangling references, race conditions. This is the highest priority — bugs and safety issues must be caught first. Do NOT nitpick internal code that relies on framework guarantees. 2. **Dead code**: Any code added or left behind that is never called or used, within the scope of the changes. Unused variables, unreachable branches, leftover scaffolding. 3. **Redundant changes**: Changes in the diff that have no functional effect — moving declarations or code blocks to a different location without reason, reformatting untouched code, reordering includes or fields with no purpose. Every line in the diff should serve the feature. If a file appears in `git diff` but contains only no-op rearrangements, flag it for revert. 4. **Code duplication**: Unnecessary repetition of logic that should be shared. Look for near-identical blocks that differ only in minor details and could be unified. 5. **Wrong placement**: Code added to a module where it doesn't logically belong. If another existing module is a clearly better fit for the new code, flag it. Consider the existing module boundaries and responsibilities visible in context.md. 6. **Function decomposition**: For longer functions (roughly 50+ lines), consider whether a logical sub-task could be cleanly extracted into a separate function. This is NOT a hard rule — a 100-line function that flows naturally and isn't easily divisible is perfectly fine. But sometimes even a 20-line function contains a clear isolated subtask that reads better as two 10-line functions. The key is to think about it each time: does extracting improve readability and reduce cognitive load, or does it just scatter logic across call sites for no real benefit? Only suggest extraction when there's a genuinely self-contained piece of logic with a clear name and purpose. 7. **Module structure**: Only in exceptional cases — if a large amount of newly added code (hundreds of lines) is logically distinct from the rest of its host module, suggest extracting it into a new module. But do NOT suggest new modules lightly: every module adds significant build overhead due to PCH and heavy template usage. Only suggest this when the new code is both large enough AND logically separated enough to justify it. At the same time, don't let modules grow into multi-thousand-line monoliths either. 8. **Style compliance**: Verify adherence to REVIEW.md rules (empty line before closing brace, operators at start of continuation lines, minimize type checks with direct cast instead of is+as, no if-with-initializer when simpler alternatives exist) and AGENTS.md conventions (no unnecessary comments, `auto` usage, no hardcoded sizes — must use .style definitions), etc. IMPORTANT GUIDELINES: - Review ONLY the changes made, not pre-existing code in the repository. - Be pragmatic. Don't suggest changes for the sake of it. Each suggestion should have a clear, concrete benefit. - Don't suggest adding comments, docstrings, or type annotations — the codebase style avoids these. - Don't suggest error handling for impossible scenarios or over-engineering. Write your review to: .ai/<project-name>/<letter>/review<R>.md The review document should contain: ## Code Review - Iteration <R> ## Summary <1-2 sentence overall assessment> ## Verdict: <APPROVED or NEEDS_CHANGES> <If APPROVED, stop here. Everything looks good.> <If NEEDS_CHANGES, continue with:> ## Changes Required ### <Issue 1 title> - **Category**: <dead code | duplication | wrong placement | function decomposition | module structure | style | correctness> - **File(s)**: <file paths> - **Problem**: <clear description of what's wrong> - **Fix**: <specific description of what to change> ### <Issue 2 title> ... Keep the list focused. Only include issues that genuinely improve the code. If you find yourself listing more than ~5-6 issues, prioritize the most impactful ones. When finished, report your verdict clearly as: APPROVED or NEEDS_CHANGES. ``` After the review agent returns, read `review<R>.md`. If the verdict is APPROVED, proceed to Completion. If NEEDS_CHANGES, spawn the fix agent. ### Step 6b: Review Fix Agent Spawn an agent (Task tool, subagent_type=`general-purpose`): ``` You are a review fix agent. You implement improvements identified during code review. Read these files: - .ai/<project-name>/<letter>/context.md - Codebase context - .ai/<project-name>/<letter>/plan.md - Original implementation plan - .ai/<project-name>/<letter>/review<R>.md - Code review with required changes Then read the source files mentioned in the review. YOUR TASK: Implement ALL changes listed in review<R>.md. For each issue in the review: 1. Read the relevant source file(s). 2. Make the specified change. 3. Verify the change makes sense in context. After all changes are made: 1. Build (from repository root): cmake --build ./out --config Debug --target Telegram 2. If the build fails, fix build errors and rebuild until it passes. 3. If build fails with file-locked errors (C1041, LNK1104), STOP and report - do not retry. Rules: - Implement exactly the changes from the review, nothing more. - Follow AGENTS.md coding conventions. - Do NOT modify .ai/ files. When finished, report what changes were made. ``` After the fix agent returns, increment R and loop back to Step 6a (unless R > 3, in which case proceed to Completion). ## Completion When all phases including build verification and code review are done: 1. Read the final `plan.md` and report the summary to the user. 2. Show which files were modified/created. 3. Note any issues encountered during implementation. 4. Summarize code review iterations: how many rounds, what was found and fixed, or if it was approved on first pass. 5. Calculate and display the total elapsed time since `$START_TIME` (format as `Xh Ym Zs`, omitting zero components — e.g. `12m 34s` or `1h 5m 12s`). 6. Remind the user of the project name so they can use `/task <project-name> <follow-up description>` for follow-up changes. ## Error Handling - If any agent fails or gets stuck, report the issue to the user and ask how to proceed. - If context.md or plan.md is not written properly by an agent, re-spawn that agent with more specific instructions. - If build errors persist after the build agent's attempts, report the remaining errors to the user. - If a review fix agent introduces new build errors that it cannot resolve, report to the user. ================================================ FILE: .claude/commands/withtest.md ================================================ --- description: Implement a feature using multi-agent workflow, then iteratively test and fix it in-app allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Task, AskUserQuestion, TodoWrite --- # WithTest - Multi-Agent Implementation + Testing Workflow You orchestrate a multi-phase implementation workflow followed by an iterative testing/fixing loop. This is an extended version of `/task` that adds in-app programmatic testing after the build succeeds. **Arguments:** `$ARGUMENTS` = "$ARGUMENTS" If `$ARGUMENTS` is provided, it's the task description. If empty, ask the user what they want implemented. ## Overview The workflow produces `.ai/<feature-name>/` containing: - `context.md` - Gathered codebase context relevant to the task - `plan.md` - Detailed implementation plan with phases and status - `testN.md` - Test plan for iteration N - `resultN.md` - Test result report for iteration N - `planN.md` - Fix plan for iteration N (if implementation bugs found) - `screenshots/` - Screenshots captured during test runs Two major stages: 1. **Implementation** (Phases 0-5) - same as `/task` 2. **Testing Loop** (Phase 6) - iterative test-plan → test-do → test-run → test-check cycle --- ## STAGE 1: IMPLEMENTATION (Phases 0-5) These phases are identical to the `/task` workflow. ### Phase 0: Setup 1. Understand the task from `$ARGUMENTS` or ask the user. 2. **Follow-up detection:** Check if `$ARGUMENTS` starts with a task name (the first word/token before any whitespace or newline). Look for `.ai/<that-name>/` directory: - If `.ai/<that-name>/` exists AND contains both `context.md` and `plan.md`, this is a **follow-up task**. Read both files. The rest of `$ARGUMENTS` (after the task name) is the follow-up task description describing what additional changes are needed. - If no matching directory exists, this is a **new task** - proceed normally. 3. For new tasks: check existing folders in `.ai/` to pick a unique short name (1-2 lowercase words, hyphen-separated) and create `.ai/<feature-name>/`. 4. For follow-up tasks: the folder already exists, skip creation. ### Follow-up Task Flow When a follow-up task is detected (existing `.ai/<name>/` with `context.md` and `plan.md`): 1. Skip Phase 1 (Context Gathering) - context already exists. 2. Skip Phase 2 (Planning) - original plan already exists. 3. Go directly to **Phase 2F (Follow-up Planning)** instead of Phase 3. **Phase 2F: Follow-up Planning** Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt: ``` You are a planning agent for a follow-up task on an existing implementation. Read these files: - .ai/<feature-name>/context.md - Previously gathered codebase context - .ai/<feature-name>/plan.md - Previous implementation plan (already completed) Then read the source files referenced in context.md and plan.md to understand what was already implemented. FOLLOW-UP TASK: <paste the follow-up task description here> The previous plan was already implemented and tested. Now there are follow-up changes needed. YOUR JOB: 1. Understand what was already done from plan.md (look at the completed phases). 2. Read the actual source files to see the current state of the code. 3. If context.md needs updates for the follow-up task (new files relevant, new patterns needed), update it with additional sections marked "## Follow-up Context (iteration 2)" or similar. 4. Create a NEW follow-up plan. Update plan.md by: - Keep the existing content as history (do NOT delete it) - Add a new section at the end: --- ## Follow-up Task <description> ## Follow-up Approach <high-level description> ## Follow-up Files to Modify <list> ## Follow-up Implementation Steps ### Phase F1: <name> 1. <specific step> 2. ... ### Phase F2: <name> (if needed) ... ## Follow-up Status Phases: <N> - [ ] Phase F1: <name> - [ ] Phase F2: <name> (if applicable) - [ ] Build verification - [ ] Testing Assessed: yes Reason carefully. The follow-up plan should be self-contained enough that an implementation agent can execute it by reading context.md and the updated plan.md. ``` After this agent completes, read `plan.md` to verify the follow-up plan was written. Then proceed to Phase 4 (Implementation), using the follow-up phases (F1, F2, etc.) instead of the original phases. After implementation and build verification, proceed to Stage 2 (Testing Loop) as normal. ### New Task Flow When this is a new task (no existing folder), proceed with Phases 1-5 as described below. ### Phase 1: Context Gathering Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure: ``` You are a context-gathering agent for a large C++ codebase (Telegram Desktop). TASK: <paste the user's task description here> YOUR JOB: Read CLAUDE.md, inspect the codebase, find ALL files and code relevant to this task, and write a comprehensive context document. Steps: 1. Read CLAUDE.md for project conventions and build instructions. 2. Search the codebase for files, classes, functions, and patterns related to the task. 3. Read all potentially relevant files. Be thorough - read more rather than less. 4. For each relevant file, note: - File path - Relevant line ranges - What the code does and how it relates to the task - Key data structures, function signatures, patterns used 5. Look for similar existing features that could serve as a reference implementation. 6. Check api.tl if the task involves Telegram API. 7. Check .style files if the task involves UI. 8. Check lang.strings if the task involves user-visible text. Write your findings to: .ai/<feature-name>/context.md The context.md should contain: - **Task Description**: The full task restated clearly - **Relevant Files**: Every file path with line ranges and descriptions of what's there - **Key Code Patterns**: How similar things are done in the codebase (with code snippets) - **Data Structures**: Relevant types, structs, classes - **API Methods**: Any TL schema methods involved (copied from api.tl) - **UI Styles**: Any relevant style definitions - **Localization**: Any relevant string keys - **Build Info**: Build command and any special notes - **Reference Implementations**: Similar features that can serve as templates Be extremely thorough. Another agent with NO prior context will read this file and must be able to understand everything needed to implement the task. ``` After this agent completes, read `context.md` to verify it was written properly. ### Phase 2: Planning Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure: ``` You are a planning agent. You must create a detailed implementation plan. Read these files: - .ai/<feature-name>/context.md - Contains all gathered context - Then read the specific source files referenced in context.md to understand the code deeply. Think carefully about the implementation approach. Create a detailed plan in: .ai/<feature-name>/plan.md The plan.md should contain: ## Task <one-line summary> ## Approach <high-level description of the implementation approach> ## Files to Modify <list of files that will be created or modified> ## Files to Create <list of new files, if any> ## Implementation Steps Each step must be specific enough that an agent can execute it without ambiguity: - Exact file paths - Exact function names - What code to add/modify/remove - Where exactly in the file (after which function, in which class, etc.) Number every step. Group steps into phases if there are more than ~8 steps. ### Phase 1: <name> 1. <specific step> 2. <specific step> ... ### Phase 2: <name> (if needed) ... ## Build Verification - Build command to run - Expected outcome ## Status - [ ] Phase 1: <name> - [ ] Phase 2: <name> (if applicable) - [ ] Build verification - [ ] Testing ``` After this agent completes, read `plan.md` to verify it was written properly. ### Phase 3: Plan Assessment Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure: ``` You are a plan assessment agent. Review and refine an implementation plan. Read these files: - .ai/<feature-name>/context.md - .ai/<feature-name>/plan.md - Then read the actual source files referenced to verify the plan makes sense. Carefully assess the plan: 1. **Correctness**: Are the file paths and line references accurate? Does the plan reference real functions and types? 2. **Completeness**: Are there missing steps? Edge cases not handled? 3. **Code quality**: Will the plan minimize code duplication? Does it follow existing codebase patterns from CLAUDE.md? 4. **Design**: Could the approach be improved? Are there better patterns already used in the codebase? 5. **Phase sizing**: Each phase should be implementable by a single agent in one session. If a phase has more than ~8-10 substantive code changes, split it further. Update plan.md with your refinements. Keep the same structure but: - Fix any inaccuracies - Add missing steps - Improve the approach if you found better patterns - Ensure phases are properly sized for single-agent execution - Add a line at the top of the Status section: `Phases: <N>` indicating how many implementation phases there are - Add `Assessed: yes` at the bottom of the file If the plan is small enough for a single agent (roughly <=8 steps), mark it as a single phase. ``` After this agent completes, read `plan.md` to verify it was assessed. ### Phase 4: Implementation Now read `plan.md` yourself to understand the phases. For each phase in the plan that is not yet marked as done, spawn an implementation agent (Task tool, subagent_type=`general-purpose`): ``` You are an implementation agent working on phase <N> of an implementation plan. Read these files first: - .ai/<feature-name>/context.md - Full codebase context - .ai/<feature-name>/plan.md - Implementation plan Then read the source files you'll be modifying. YOUR TASK: Implement ONLY Phase <N> from the plan: <paste the specific phase steps here> Rules: - Follow the plan precisely - Follow CLAUDE.md coding conventions (no comments except complex algorithms, use auto, empty line before closing brace, etc.) - Do NOT modify .ai/ files except to update the Status section in plan.md - When done, update plan.md Status section: change `- [ ] Phase <N>: ...` to `- [x] Phase <N>: ...` - Do NOT work on other phases When finished, report what you did and any issues encountered. ``` After each implementation agent returns: 1. Read `plan.md` to check the status was updated. 2. If more phases remain, spawn the next implementation agent. 3. If all phases are done, proceed to build verification. ### Phase 5: Build Verification Spawn a build verification agent (Task tool, subagent_type=`general-purpose`): ``` You are a build verification agent. Read these files: - .ai/<feature-name>/context.md - .ai/<feature-name>/plan.md The implementation is complete. Your job is to build the project and fix any build errors. Steps: 1. Run: cmake --build "c:\Telegram\tdesktop\out" --config Debug --target Telegram 2. If the build succeeds, update plan.md: change `- [ ] Build verification` to `- [x] Build verification` 3. If the build fails: a. Read the error messages carefully b. Read the relevant source files c. Fix the errors in accordance with the plan and CLAUDE.md conventions d. Rebuild and repeat until the build passes e. Update plan.md status when done Rules: - Only fix build errors, do not refactor or improve code - Follow CLAUDE.md conventions - If build fails with file-locked errors (C1041, LNK1104), STOP and report - do not retry When finished, report the build result. ``` After the build agent returns, read `plan.md` to confirm build verification passed. If it did, proceed to Stage 2. --- ## STAGE 2: TESTING LOOP (Phase 6) This stage iteratively tests the implementation in-app and fixes issues. It maintains an iteration counter `N` starting at 1. **Key concept:** Since the project has tight coupling and no unit test infrastructure, we test by injecting `#ifdef _DEBUG` blocks into the app code that perform actions, write to `log.txt`, save screenshots, and call `Core::Quit()` when done. An agent then runs the app and observes the output. ### Git Submodule Awareness Before ANY git operation (commit, stash, stash pop), the agent must: 1. Run `git submodule status` to check for modified submodules. 2. If submodules have changes, commit/stash those submodules FIRST, individually: ``` cd <submodule-path> && git add -A && git commit -m "[wip-N] test changes" && cd <repo-root> ``` or for stash: ``` cd <submodule-path> && git stash && cd <repo-root> ``` 3. Then operate on the main repo. ### Step 6a: Test Plan (test-plan agent) Spawn an agent (Task tool, subagent_type=`general-purpose`): ``` You are a test-planning agent for Telegram Desktop (C++ / Qt). Read these files: - .ai/<feature-name>/context.md - .ai/<feature-name>/plan.md <if N > 1, also include:> - .ai/<feature-name>/result<N-1>.md - Previous test result <if a planN.md triggered this iteration:> - .ai/<feature-name>/plan<trigger>.md - Fix plan that was just implemented CURRENT ITERATION: <N> YOUR TASKS: 1. **Commit current implementation changes.** - Run `git submodule status` to check for modified submodules. - If any submodules are dirty, go into each one and commit: `cd <submodule> && git add -A && git commit -m "[wip-<N>]" && cd <repo-root>` - Then in main repo: `git add -A && git commit -m "[wip-<N>]"` - Do NOT add files in .ai/ to the commit. 2. <If N > 1> **Restore previous test code.** - Run `git submodule status` and `git stash list` in any dirty submodules to check for stashed test code. - Pop submodule stashes first: `cd <submodule> && git stash pop && cd <repo-root>` - Then pop main repo stash: `git stash pop` - Read the previous test<N-1>.md to understand what was tested before. - Decide: reuse/modify existing test code or start fresh. 3. **Plan the test code.** Carefully design test code that will verify the implementation works correctly. The test code must: - Be wrapped in `#ifdef _DEBUG` blocks so it only runs in Debug builds - Be injected at appropriate points in the app lifecycle (e.g., after main window shows, after chats load, etc.) - Write progress and results to a log file. Use a dedicated path like: `QFile logFile("c:/Telegram/tdesktop/.ai/<feature-name>/test_log.txt");` Open with `QIODevice::Append | QIODevice::Text`, write with QTextStream, and flush after every write. - Save screenshots where visual verification is needed: `widget->grab().save("c:/Telegram/tdesktop/.ai/<feature-name>/screenshots/<name>.png");` Log each screenshot save: `"SCREENSHOT: <full-path>"` - Use `QTimer::singleShot(...)` or deferred calls to schedule test steps after UI events settle - Call `Core::Quit()` when all test steps complete, so the app exits cleanly - Log `"TEST_COMPLETE"` right before `Core::Quit()` so the test-run agent knows testing finished - Log `"TEST_STEP: <description>"` before each major step for progress tracking - Log `"TEST_RESULT: PASS: <what>"` or `"TEST_RESULT: FAIL: <what> - <details>"` for each check Consider what needs testing: - Does the new UI appear correctly? - Do interactions work (clicks, navigation)? - Does data flow correctly? - Are there edge cases to verify? 4. **Write the test plan** to `.ai/<feature-name>/test<N>.md` containing: ## Test Iteration <N> ## What We're Testing <description of what this test verifies> ## Test Steps 1. <step>: what we do, what we expect, how we verify 2. ... ## Code Injection Points - File: <path>, Location: <where in file>, Purpose: <what this block does> - ... ## Expected Log Output <example of what test_log.txt should contain if everything works> ## Expected Screenshots - <name>.png: should show <description> - ... ## Success Criteria - <criterion 1> - <criterion 2> - ... When finished, report what test plan was created. ``` ### Step 6b: Test Implementation (test-do agent) Spawn an agent (Task tool, subagent_type=`general-purpose`): ``` You are a test implementation agent for Telegram Desktop (C++ / Qt). Read these files: - .ai/<feature-name>/context.md - .ai/<feature-name>/plan.md - .ai/<feature-name>/test<N>.md - The test plan to implement YOUR TASK: Implement the test code described in test<N>.md. Rules: - ALL test code MUST be inside `#ifdef _DEBUG` blocks - Place test code at the injection points specified in the test plan - Make sure the screenshots folder exists: create `.ai/<feature-name>/screenshots/` directory - Delete any old test_log.txt before the test starts (in code, at the first test step) - Use QTimer::singleShot for delayed operations to let the UI settle - Flush log writes immediately (don't buffer) - End with logging "TEST_COMPLETE" and calling Core::Quit() - Follow CLAUDE.md coding conventions - Make sure the code compiles: run `cmake --build "c:\Telegram\tdesktop\out" --config Debug --target Telegram` - If build fails, fix errors and rebuild until it passes - If build fails with file-locked errors (C1041, LNK1104), STOP and report When finished, report what test code was added and where. ``` ### Step 6c: Test Run (test-run agent) Spawn an agent (Task tool, subagent_type=`general-purpose`): ``` You are a test execution agent. You run the Telegram Desktop app and observe test output. Read these files: - .ai/<feature-name>/test<N>.md - The test plan (so you know what to expect) YOUR TASK: Run the built app and monitor test execution. Steps: 1. **Prepare.** - Delete old test_log.txt if it exists: `del "c:\Telegram\tdesktop\docs\ai\work\<feature-name>\test_log.txt" 2>nul` - Ensure screenshots folder exists: `mkdir "c:\Telegram\tdesktop\docs\ai\work\<feature-name>\screenshots" 2>nul` 2. **Launch the app.** - Run in background: `start "" "c:\Telegram\tdesktop\out\Debug\Telegram.exe"` - Note the time of launch. 3. **Monitor test_log.txt in a polling loop.** - Every 5 seconds, read the log file to check for new output. - When you see `"SCREENSHOT: <path>"`, read the screenshot image file to visually verify it. - Track which TEST_STEP entries appear. - Track TEST_RESULT entries (PASS/FAIL). 4. **Detect completion or failure.** - **Success**: Log contains `"TEST_COMPLETE"` - the app should exit on its own shortly after. - **Crash**: The process disappears before `"TEST_COMPLETE"`. Check for crash dumps or error dialogs. - **Hang/Timeout**: If no new log output for 120 seconds and no `"TEST_COMPLETE"`, kill the process: `taskkill /IM Telegram.exe /F` - **No log at all**: If no test_log.txt appears within 60 seconds of launch, kill the process. 5. **After the process exits (or is killed), wait 5 seconds, then:** - Read the full final test_log.txt - Read all screenshot files saved during the test - Check for any leftover Telegram.exe processes: `tasklist /FI "IMAGENAME eq Telegram.exe"` and kill if needed 6. **Write the result report** to `.ai/<feature-name>/result<N>.md`: ## Test Result - Iteration <N> ## Outcome: <PASS / FAIL / CRASH / TIMEOUT> ## Log Output <full contents of test_log.txt, or note that it was empty/missing> ## Screenshot Analysis - <name>.png: <description of what you see, whether it matches expectations from test<N>.md> - ... ## Test Results Summary - PASS: <list> - FAIL: <list> ## Issues Found <any problems observed, unexpected behavior, etc.> ## Raw Details <process exit code if available, timing information, any stderr output> When finished, report the test outcome. ``` After the test-run agent returns, read `result<N>.md`. ### Step 6d: Test Assessment (test-check agent) Spawn an agent (Task tool, subagent_type=`general-purpose`): ``` You are a test assessment agent. You analyze test results and decide next steps. Read these files: - .ai/<feature-name>/context.md - .ai/<feature-name>/plan.md - .ai/<feature-name>/test<N>.md - .ai/<feature-name>/result<N>.md <if N > 1, also read previous test/result pairs for history> Carefully analyze the test results. DECIDE one of three outcomes: ### Outcome A: ALL TESTS PASS If all test results are PASS and screenshots look correct: 1. Write to result<N>.md (append): `\n## Verdict: PASS` 2. Report "ALL_TESTS_PASS" so the orchestrator knows to finish. ### Outcome B: TEST CODE NEEDS CHANGES If the test itself was flawed (wrong assertions, bad timing, insufficient waits, screenshot taken too early, wrong injection point, etc.) but the implementation seems correct: 1. Describe what's wrong with the test and what to change. 2. Make the changes directly to the test code in the source files. 3. Rebuild: `cmake --build "c:\Telegram\tdesktop\out" --config Debug --target Telegram` 4. If build fails with file-locked errors (C1041, LNK1104), STOP and report. 5. Write the updated test description to `.ai/<feature-name>/test<N+1>.md` explaining what changed and why. 6. Report "TEST_NEEDS_RERUN" so the orchestrator goes back to step 6c. ### Outcome C: IMPLEMENTATION HAS BUGS If the test results indicate actual bugs in the implementation (not test issues): 1. Analyze what's wrong with the implementation. 2. Write a fix plan to `.ai/<feature-name>/plan<N>.md`: ## Fix Plan - Iteration <N> ## Problem <what the test revealed> ## Root Cause <analysis of why the implementation is wrong> ## Fix Steps 1. <specific fix with file path, location, what to change> 2. ... 3. Stash the test code (it will be restored later): - Run `git submodule status` and stash dirty submodules first: `cd <submodule> && git stash && cd <repo-root>` - Then: `git stash` 4. Report "IMPLEMENTATION_NEEDS_FIX" so the orchestrator goes to re-implementation. When finished, report your verdict clearly as one of: ALL_TESTS_PASS, TEST_NEEDS_RERUN, IMPLEMENTATION_NEEDS_FIX. ``` ### Orchestrator Loop Logic After Phase 5 (build verification) succeeds, you (the orchestrator) run the testing loop: ``` Set N = 1 LOOP: 1. Spawn test-plan agent (Step 6a) with iteration N 2. Spawn test-do agent (Step 6b) with iteration N 3. Spawn test-run agent (Step 6c) with iteration N 4. Spawn test-check agent (Step 6d) with iteration N 5. Read the verdict: - "ALL_TESTS_PASS" → go to FINISH - "TEST_NEEDS_RERUN" → N = N + 1 go to step 3 (skip 6a and 6b, test code was already updated by test-check) - "IMPLEMENTATION_NEEDS_FIX" → Spawn implementation fix agent (see below) N = N + 1 go to step 1 (full restart: new commit, stash pop test code, etc.) 6. Safety: if N > 5, stop and report to user - too many iterations. FINISH: - Stash or revert all test code (#ifdef _DEBUG blocks): - git submodule status, stash submodules if dirty - git stash (to save test code separately, user may want it later) - Update plan.md: change `- [ ] Testing` to `- [x] Testing` - Report to user ``` ### Implementation Fix Agent When test-check reports IMPLEMENTATION_NEEDS_FIX, spawn this agent: ``` You are an implementation fix agent. Read these files: - .ai/<feature-name>/context.md - .ai/<feature-name>/plan.md - .ai/<feature-name>/plan<N>.md - The fix plan from test assessment Then read the source files mentioned in the fix plan. YOUR TASK: Implement the fixes described in plan<N>.md. Steps: 1. Read and understand the fix plan. 2. Make the specified code changes. 3. Build: `cmake --build "c:\Telegram\tdesktop\out" --config Debug --target Telegram` 4. Fix any build errors. 5. If build fails with file-locked errors (C1041, LNK1104), STOP and report. Rules: - Only make changes specified in the fix plan - Follow CLAUDE.md conventions - Do NOT touch test code or .ai/ files (except plan.md status if relevant) When finished, report what was fixed. ``` --- ## Completion When the testing loop finishes (ALL_TESTS_PASS or user stops it): 1. Read the final `plan.md` and report full summary to the user. 2. List all files modified/created by the implementation. 3. Summarize test iterations: how many rounds, what was found and fixed. 4. Note that test code is stashed (available via `git stash pop` if needed). 5. Note any remaining concerns. ## Error Handling - If any agent fails or gets stuck, report the issue to the user and ask how to proceed. - If context.md or plan.md is not written properly by an agent, re-spawn that agent with more specific instructions. - If build errors persist after agent attempts, report remaining errors to the user. - If the testing loop exceeds 5 iterations, stop and report - something fundamental may be wrong. - If the app crashes repeatedly, report to user - may need manual investigation. - If file-locked build errors occur at ANY point, stop immediately and ask user to close Telegram.exe. ================================================ FILE: .claude/grab_clipboard.ps1 ================================================ param([string]$outPath) Add-Type -AssemblyName System.Windows.Forms $img = [System.Windows.Forms.Clipboard]::GetImage() if ($img) { $img.Save($outPath, [System.Drawing.Imaging.ImageFormat]::Png) Write-Host "Saved to $outPath" exit 0 } else { Write-Host "No image on clipboard" exit 1 } ================================================ FILE: .claude/grab_clipboard.sh ================================================ #!/bin/bash # Grab clipboard image on macOS and save as PNG. outPath="$1" if [ -z "$outPath" ]; then echo "Usage: grab_clipboard.sh <output.png>" exit 1 fi osascript -e ' set theFile to POSIX file "'"$outPath"'" try set theImage to the clipboard as «class PNGf» on error return "no image" end try set fh to open for access theFile with write permission write theImage to fh close access fh return "ok" ' 2>/dev/null | grep -q "ok" if [ $? -eq 0 ]; then echo "Saved to $outPath" exit 0 else echo "No image on clipboard" exit 1 fi ================================================ FILE: .claude/iterate.ps1 ================================================ #!/usr/bin/env pwsh # Iterative Task Runner # Runs Claude Code in a loop to complete tasks from a taskplanner-created folder # # Usage: .\docs\ai\iterate.ps1 <featurename> [-MaxIterations N] [-Interactive] [-DryRun] [-SingleCommit] [-NoCommit] # # Arguments: # featurename Name of the folder in .ai/ containing prompt.md and tasks.json # -MaxIterations Maximum iterations before stopping (default: 50) # -Interactive Pause between iterations for user confirmation (default: auto/no pause) # -DryRun Show what would be executed without running # -SingleCommit Don't commit after each task, commit all changes at the end # -NoCommit Don't commit at all (no per-task commits, no final commit) param( [Parameter(Position=0, Mandatory=$true)] [string]$FeatureName, [int]$MaxIterations = 50, [switch]$Interactive, [switch]$DryRun, [switch]$SingleCommit, [switch]$NoCommit ) $ErrorActionPreference = "Stop" $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $RepoRoot = Resolve-Path (Join-Path $ScriptDir "..\..") $WorkDir = Join-Path $ScriptDir "work\$FeatureName" $PromptMd = Join-Path $WorkDir "prompt.md" $TasksJson = Join-Path $WorkDir "tasks.json" $BuildOutputDir = Join-Path $RepoRoot "out\Debug" $TelegramExe = Join-Path $BuildOutputDir "Telegram.exe" $TelegramPdb = Join-Path $BuildOutputDir "Telegram.pdb" function Format-Duration { param([int]$Seconds) if ($Seconds -lt 60) { return "${Seconds}s" } elseif ($Seconds -lt 3600) { $min = [math]::Floor($Seconds / 60) $sec = $Seconds % 60 return "${min}m ${sec}s" } else { $hr = [math]::Floor($Seconds / 3600) $min = [math]::Floor(($Seconds % 3600) / 60) $sec = $Seconds % 60 return "${hr}h ${min}m ${sec}s" } } function Test-BuildFilesUnlocked { $filesToCheck = @($TelegramExe, $TelegramPdb) foreach ($file in $filesToCheck) { if (Test-Path $file) { try { Remove-Item $file -Force -ErrorAction Stop Write-Host "Removed: $file" -ForegroundColor DarkGray } catch { Write-Host "" Write-Host "========================================" -ForegroundColor Red Write-Host " ERROR: Cannot delete build output" -ForegroundColor Red Write-Host " File is locked: $file" -ForegroundColor Red Write-Host "" -ForegroundColor Red Write-Host " Please close Telegram.exe and any" -ForegroundColor Red Write-Host " debugger, then try again." -ForegroundColor Red Write-Host "========================================" -ForegroundColor Red Write-Host "" return $false } } } return $true } function Show-ClaudeStream { param([string]$Line) try { $obj = $Line | ConvertFrom-Json -ErrorAction Stop switch ($obj.type) { "assistant" { if ($obj.message.content) { foreach ($block in $obj.message.content) { if ($block.type -eq "text") { Write-Host $block.text -ForegroundColor White } elseif ($block.type -eq "tool_use") { $summary = "" if ($block.input) { if ($block.input.file_path) { $summary = $block.input.file_path } elseif ($block.input.pattern) { $summary = $block.input.pattern } elseif ($block.input.command) { $cmd = $block.input.command if ($cmd.Length -gt 60) { $cmd = $cmd.Substring(0, 60) + "..." } $summary = $cmd } else { $inputStr = $block.input | ConvertTo-Json -Compress -Depth 1 if ($inputStr.Length -gt 60) { $inputStr = $inputStr.Substring(0, 60) + "..." } $summary = $inputStr } } Write-Host "[Tool: $($block.name)] $summary" -ForegroundColor Yellow } } } } "user" { # Tool results - skip verbose output } "result" { Write-Host "`n--- Session Complete ---" -ForegroundColor Cyan if ($obj.cost_usd) { Write-Host "Cost: `$$($obj.cost_usd)" -ForegroundColor DarkCyan } } "system" { # System messages - skip } } } catch { # Not valid JSON, skip } } # Verify feature folder exists if (-not (Test-Path $WorkDir)) { Write-Error "Feature folder not found: $WorkDir`nRun '/taskplanner $FeatureName' first to create it." exit 1 } # Verify required files exist foreach ($file in @($PromptMd, $TasksJson)) { if (-not (Test-Path $file)) { Write-Error "Required file not found: $file" exit 1 } } if ($SingleCommit -or $NoCommit) { $AfterImplementation = @" - Mark the task completed in tasks.json ("completed": true) - If new tasks emerged, add them to tasks.json "@ $CommitRule = "- Do NOT commit changes after task is done, just mark it as done in tasks.json. Commit will be done when all tasks are complete, separately." } else { $AfterImplementation = @" - Mark the task completed in tasks.json ("completed": true) - Commit your changes - If new tasks emerged, add them to tasks.json "@ $CommitRule = "" } $Prompt = @" You are an autonomous coding agent working on: $FeatureName Read these files for context: - .ai/$FeatureName/prompt.md - Detailed instructions and architecture - .ai/$FeatureName/tasks.json - Task list with completion status Do exactly ONE task per iteration. ## Steps 1. Read tasks.json and find the most suitable task to implement (it can be first uncompleted task or it can be some task in the middle, if it is better suited to be implemented right now, respecting dependencies) 2. Plan the implementation carefully 3. Implement that ONE task only 4. After successful implementation: $AfterImplementation ## Critical Rules - Only mark a task complete if you verified the work is done (build passes, etc.) - If stuck, document the issue in the task's notes field and move on - Do ONE task per iteration, then stop - NEVER try to commit files in .ai/ $CommitRule ## Completion Signal If ALL tasks in tasks.json have "completed": true, output exactly: ===ALL_TASKS_COMPLETE=== "@ $CommitPrompt = @" You are an autonomous coding agent. All tasks for "$FeatureName" are now complete. Your job: Create a single commit with all the changes. ## Steps 1. Run git status to see all modified files 2. Run git diff to review the changes 3. Create a commit with a short summary (aim for ~50 chars, max 76 chars) describing what was implemented 4. The commit message should describe the overall feature/fix, not list individual changes ## Critical Rules - NEVER try to commit files in .ai/ - Use a concise commit message that captures the essence of the work done "@ Write-Host "" Write-Host "========================================" -ForegroundColor Cyan Write-Host " Iterative Task Runner" -ForegroundColor Cyan Write-Host " Feature: $FeatureName" -ForegroundColor Cyan Write-Host " Max iterations: $MaxIterations" -ForegroundColor Cyan Write-Host " Mode: $(if ($Interactive) { 'Interactive' } else { 'Auto' })" -ForegroundColor Cyan Write-Host " Commit: $(if ($NoCommit) { 'None' } elseif ($SingleCommit) { 'Single (at end)' } else { 'Per task' })" -ForegroundColor Cyan Write-Host " Working directory: $RepoRoot" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" if ($DryRun) { Write-Host "[DRY RUN] Would execute with prompt:" -ForegroundColor Yellow Write-Host $Prompt Write-Host "" Write-Host "Feature folder: $WorkDir" -ForegroundColor Yellow Write-Host "Prompt file: $PromptMd" -ForegroundColor Yellow Write-Host "Tasks file: $TasksJson" -ForegroundColor Yellow exit 0 } Push-Location $RepoRoot $ScriptStartTime = Get-Date $IterationTimes = @() try { for ($i = 1; $i -le $MaxIterations; $i++) { Write-Host "" Write-Host "========================================" -ForegroundColor Yellow Write-Host " Iteration $i of $MaxIterations" -ForegroundColor Yellow Write-Host "========================================" -ForegroundColor Yellow Write-Host "" if (-not (Test-BuildFilesUnlocked)) { exit 1 } $IterationStartTime = Get-Date claude --dangerously-skip-permissions --verbose -p $Prompt --output-format stream-json 2>&1 | ForEach-Object { Show-ClaudeStream $_ } $IterationEndTime = Get-Date $IterationDuration = [int]($IterationEndTime - $IterationStartTime).TotalSeconds $IterationTimes += $IterationDuration Write-Host "Iteration time: $(Format-Duration $IterationDuration)" -ForegroundColor DarkCyan # Check task status after each run $tasks = Get-Content $TasksJson | ConvertFrom-Json $incomplete = @($tasks.tasks | Where-Object { -not $_.completed }) $inProgress = @($tasks.tasks | Where-Object { $_.started -and -not $_.completed }) if ($incomplete.Count -eq 0) { if ($SingleCommit -and -not $NoCommit) { $i++ if ($i -le $MaxIterations) { Write-Host "" Write-Host "========================================" -ForegroundColor Yellow Write-Host " Final commit iteration" -ForegroundColor Yellow Write-Host "========================================" -ForegroundColor Yellow Write-Host "" $CommitStartTime = Get-Date claude --dangerously-skip-permissions --verbose -p $CommitPrompt --output-format stream-json 2>&1 | ForEach-Object { Show-ClaudeStream $_ } $CommitEndTime = Get-Date $CommitDuration = [int]($CommitEndTime - $CommitStartTime).TotalSeconds $IterationTimes += $CommitDuration Write-Host "Commit time: $(Format-Duration $CommitDuration)" -ForegroundColor DarkCyan } else { Write-Host "" Write-Host "========================================" -ForegroundColor Red Write-Host " Max iterations reached before commit" -ForegroundColor Red Write-Host " Run manually: git add . && git commit" -ForegroundColor Red Write-Host "========================================" -ForegroundColor Red Write-Host "" exit 1 } } $TotalTime = [int]((Get-Date) - $ScriptStartTime).TotalSeconds $AvgTime = if ($IterationTimes.Count -gt 0) { [int](($IterationTimes | Measure-Object -Sum).Sum / $IterationTimes.Count) } else { 0 } Write-Host "" Write-Host "========================================" -ForegroundColor Green Write-Host " ALL TASKS COMPLETE!" -ForegroundColor Green Write-Host " Feature: $FeatureName" -ForegroundColor Green Write-Host " Iterations: $($IterationTimes.Count)" -ForegroundColor Green Write-Host " Total time: $(Format-Duration $TotalTime)" -ForegroundColor Green Write-Host " Avg per iteration: $(Format-Duration $AvgTime)" -ForegroundColor Green Write-Host "========================================" -ForegroundColor Green Write-Host "" exit 0 } Write-Host "" Write-Host "Remaining tasks: $($incomplete.Count)" -ForegroundColor Cyan if ($inProgress.Count -gt 0) { Write-Host "In progress: $($inProgress[0].title)" -ForegroundColor Yellow } if ($Interactive) { Write-Host "Press Enter to continue, Ctrl+C to stop..." -ForegroundColor Cyan Read-Host } else { Start-Sleep -Seconds 2 } } $TotalTime = [int]((Get-Date) - $ScriptStartTime).TotalSeconds $AvgTime = if ($IterationTimes.Count -gt 0) { [int](($IterationTimes | Measure-Object -Sum).Sum / $IterationTimes.Count) } else { 0 } Write-Host "" Write-Host "========================================" -ForegroundColor Red Write-Host " Max iterations ($MaxIterations) reached" -ForegroundColor Red Write-Host " Check tasks.json for remaining tasks" -ForegroundColor Red Write-Host " Total time: $(Format-Duration $TotalTime)" -ForegroundColor Red Write-Host " Avg per iteration: $(Format-Duration $AvgTime)" -ForegroundColor Red Write-Host "========================================" -ForegroundColor Red Write-Host "" exit 1 } finally { Pop-Location } ================================================ FILE: .cursorignore ================================================ # Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv) Telegram/ThirdParty/ ================================================ FILE: .devcontainer.json ================================================ { "name": "CentOS", "image": "tdesktop:centos_env", "customizations": { "vscode": { "settings": { "C_Cpp.intelliSenseEngine": "disabled", "cmake.generator": "Ninja Multi-Config", "cmake.buildDirectory": "${workspaceFolder}/out", "cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json" }, "extensions": [ "ms-vscode.cpptools-extension-pack", "llvm-vs-code-extensions.vscode-clangd", "TheQtCompany.qt", "ms-python.python", "ms-azuretools.vscode-docker", "eamodio.gitlens" ] } }, "capAdd": [ "SYS_PTRACE" ], "securityOpt": [ "seccomp=unconfined" ], "workspaceMount": "source=${localWorkspaceFolder},target=/usr/src/tdesktop,type=bind,consistency=cached", "workspaceFolder": "/usr/src/tdesktop" } ================================================ FILE: .gitattributes ================================================ # Set the default behavior, in case people don't have core.autocrlf set. * text=auto # Ensure diffs have LF endings *.diff text eol=lf *.bat text eol=crlf # Ensure lottie animations are treated as binary files *.lottie binary ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Contributing This document describes how you can contribute to Telegram Desktop. Please read it carefully. **Table of Contents** * [What contributions are accepted](#what-contributions-are-accepted) * [Build instructions](#build-instructions) * [Pull upstream changes into your fork regularly](#pull-upstream-changes-into-your-fork-regularly) * [How to get your pull request accepted](#how-to-get-your-pull-request-accepted) * [Keep your pull requests limited to a single issue](#keep-your-pull-requests-limited-to-a-single-issue) * [Squash your commits to a single commit](#squash-your-commits-to-a-single-commit) * [Don't mix code changes with whitespace cleanup](#dont-mix-code-changes-with-whitespace-cleanup) * [Keep your code simple!](#keep-your-code-simple) * [Test your changes!](#test-your-changes) * [Write a good commit message](#write-a-good-commit-message) ## What contributions are accepted We highly appreciate your contributions in the matter of fixing bugs and optimizing the Telegram Desktop source code and its documentation. In case of fixing the existing user experience please push to your fork and [submit a pull request][pr]. Wait for us. We try to review your pull requests as fast as possible. If we find issues with your pull request, we may suggest some changes and improvements. Unfortunately we **do not merge** any pull requests that have new feature implementations, translations to new languages and those which introduce any new user interface elements. If you have a translations-related contribution, check out [Translations platform][translate]. Telegram Desktop is not a standalone application but a part of [Telegram project][telegram], so all the decisions about the features, languages, user experience, user interface and the design are made inside Telegram team, often according to some roadmap which is not public. ## Build instructions See the [README.md][build_instructions] for details on the various build environments. ## Pull upstream changes into your fork regularly Telegram Desktop is advancing quickly. It is therefore critical that you pull upstream changes into your fork on a regular basis. Nothing is worse than putting in a days of hard work into a pull request only to have it rejected because it has diverged too far from upstream. To pull in upstream changes: git remote add upstream https://github.com/telegramdesktop/tdesktop.git git fetch upstream master Check the log to be sure that you actually want the changes, before merging: git log upstream/master Then rebase your changes on the latest commits in the `master` branch: git rebase upstream/master After that, you have to force push your commits: git push --force For more info, see [GitHub Help][help_fork_repo]. ## How to get your pull request accepted We want to improve Telegram Desktop with your contributions. But we also want to provide a stable experience for our users and the community. Follow these rules and you should succeed without a problem! ### Keep your pull requests limited to a single issue Pull requests should be as small/atomic as possible. Large, wide-sweeping changes in a pull request will be **rejected**, with comments to isolate the specific code in your pull request. Some examples: * If you are making spelling corrections in the docs, don't modify other files. * If you are adding new functions don't '*cleanup*' unrelated functions. That cleanup belongs in another pull request. #### Squash your commits to a single commit To keep the history of the project clean, you should make one commit per pull request. If you already have multiple commits, you can add the commits together (squash them) with the following commands in Git Bash: 1. Open `Git Bash` (or `Git Shell`) 2. Enter following command to squash the recent {N} commits: `git reset --soft HEAD~{N} && git commit` (replace `{N}` with the number of commits you want to squash) 3. Press <kbd>i</kbd> to get into Insert-mode 4. Enter the commit message of the new commit 5. After adding the message, press <kbd>ESC</kbd> to get out of the Insert-mode 6. Write `:wq` and press <kbd>Enter</kbd> to save the new message or write `:q!` to discard your changes 7. Enter `git push --force` to push the new commit to the remote repository For example, if you want to squash the last 5 commits, use `git reset --soft HEAD~5 && git commit` ### Don't mix code changes with whitespace cleanup If you change two lines of code and correct 200 lines of whitespace issues in a file the diff on that pull request is functionally unreadable and will be **rejected**. Whitespace cleanups need to be in their own pull request. ### Keep your code simple! Please keep your code as clean and straightforward as possible. Furthermore, the pixel shortage is over. We want to see: * `opacity` instead of `o` * `placeholder` instead of `ph` * `myFunctionThatDoesThings()` instead of `mftdt()` ### Test your changes! Before you submit a pull request, please test your changes. Verify that Telegram Desktop still works and your changes don't cause other issue or crashes. ### Write a good commit message * Explain why you make the changes. [More infos about a good commit message.][commit_message] * If you fix an issue with your commit, please close the issue by [adding one of the keywords and the issue number][closing-issues-via-commit-messages] to your commit message. For example: `Fix #545` [//]: # (LINKS) [telegram]: https://telegram.org/ [help_fork_repo]: https://help.github.com/articles/fork-a-repo/ [help_change_commit_message]: https://help.github.com/articles/changing-a-commit-message/ [commit_message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html [pr]: https://github.com/telegramdesktop/tdesktop/compare [build_instructions]: https://github.com/telegramdesktop/tdesktop/blob/master/README.md#build-instructions [closing-issues-via-commit-messages]: https://help.github.com/articles/closing-issues-via-commit-messages/ [translate]: https://translations.telegram.org ================================================ FILE: .github/ISSUE_TEMPLATE/BUG_REPORT.yml ================================================ name: Bug report description: Report errors or unexpected behavior. labels: [bug] body: - type: markdown attributes: value: | Thanks for reporting issues of Telegram Desktop! To make it easier for us to help you please enter detailed information below. - type: textarea attributes: label: Steps to reproduce placeholder: | 1. 2. 3. validations: required: true - type: textarea attributes: label: Expected behaviour placeholder: Tell us what should happen validations: required: true - type: textarea attributes: label: Actual behaviour placeholder: Tell us what happens instead validations: required: true - type: input attributes: label: Operating system description: > Your operating system name, version and desktop environment. **Don't use kernel version (uname), it's useless.** validations: required: true - type: input attributes: label: Version of Telegram Desktop description: > Please note we don't support versions from Linux distro repositories. If you need support for these versions, **please contact your distro maintainer** or your distro bugtracker. **Don't use 'latest'**, specify actual version, **that's a reason to close your issue**. validations: required: true - type: dropdown attributes: label: Installation source multiple: false options: - Static binary from official website - Microsoft Store - Mac App Store - Flatpak - Snap - Other (unofficial) source validations: required: true - type: input attributes: label: Crash ID description: > If you're reporting a crash, please enter the crash ID from the crash reporter opening on the next launch after crash. **You have to enable beta versions installation in Settings -> Advanced for the reporter to appear.** You don't have to wait for a beta version to arrive. - type: textarea attributes: label: Logs description: > You can find log.txt using the `viewlogs` [cheat code](https://github.com/telegramdesktop/tdesktop/wiki/Cheat-Codes). placeholder: Insert log.txt here (if necessary) render: shell ================================================ FILE: .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml ================================================ --- name: Feature request description: Suggest an idea. labels: [enhancement] body: - type: textarea attributes: label: Is your feature request related to a problem? placeholder: A clear and concise description of what the problem is. validations: required: true - type: textarea attributes: label: Describe the solution you'd like placeholder: A clear and concise description of what you want to happen. validations: required: true - type: textarea attributes: label: Describe alternatives you've considered placeholder: A clear and concise description of any alternative solutions or features you've considered. validations: required: true - type: textarea attributes: label: Additional context placeholder: Add any other context or screenshots about the feature request here. validations: required: false ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Platform-wide issue url: https://bugs.telegram.org about: Any bug report or feature request affecting more than only Telegram Desktop. - name: Issue of other client url: https://bugs.telegram.org about: Any bug report or feature request not about Telegram Desktop. - name: Question url: https://t.me/TelegramDesktopTalk about: Ask a question. ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" ================================================ FILE: .github/scripts/generate_changelog.py ================================================ #!/usr/bin/env python3 """Convert changelog.txt to a static HTML page for GitHub Pages.""" import re import shutil import sys import html from pathlib import Path MONTHS = [ "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ] VERSION_RE = re.compile( r"^(\d+\.\d+(?:\.\d+)?)\s*" # version number r"(?:(alpha|beta|dev|stable)\s*)?" # optional tag r"\((\d{2})\.(\d{2})\.(\d{2,4})\)$" # date (DD.MM.YY or DD.MM.YYYY) ) def parse_date(day: str, month: str, year: str) -> tuple[str, str, str]: """Return (sort_key, raw_display, full_display) from DD, MM, YY strings.""" y = int(year) if y < 100: y += 2000 m = int(month) d = int(day) sort_key = f"{y:04d}-{m:02d}-{d:02d}" raw_display = f"{day}.{month}.{year}" full_display = f"{d} {MONTHS[m]} {y}" return sort_key, raw_display, full_display def parse_changelog(text: str) -> list[dict]: entries = [] current = None for raw_line in text.splitlines(): line = raw_line.rstrip() m = VERSION_RE.match(line) if m: if current: entries.append(current) version, tag, day, month, year = m.groups() sort_key, raw_date, full_date = parse_date(day, month, year) current = { "version": version, "tag": tag or "", "date": raw_date, "full_date": full_date, "sort_key": sort_key, "lines": [], } elif current is not None: # Skip blank lines at the start if not line and not current["lines"]: continue # Skip stray artifact lines if line.strip() in ("),", "),"): continue current["lines"].append(line) if current: entries.append(current) # Trim trailing blank lines from each entry for entry in entries: while entry["lines"] and not entry["lines"][-1]: entry["lines"].pop() return entries def render_entry(entry: dict) -> str: version = html.escape(entry["version"]) tag = entry["tag"] date = html.escape(entry["date"]) anchor = f"v{version}" tag_html = "" if tag and tag not in ("stable",): tag_html = f' {html.escape(tag)}' parts = [ f'<article class="entry" id="{anchor}">', f' <h2><a class="anchor" href="#{anchor}"></a>' f'{version}{tag_html}' f' <time>{date}</time></h2>', ] in_list = False for line in entry["lines"]: stripped = line.lstrip() if stripped.startswith("- ") or stripped.startswith("\u2014 "): # Bullet point (- or em dash) if not in_list: parts.append(" <ul>") in_list = True bullet_text = stripped[2:] parts.append(f" <li>{html.escape(bullet_text)}</li>") else: if in_list: parts.append(" </ul>") in_list = False if stripped: parts.append(f" <p>{html.escape(stripped)}</p>") if in_list: parts.append(" </ul>") parts.append("</article>") return "\n".join(parts) def build_html(entries: list[dict]) -> str: count = len(entries) first_date = entries[-1]["full_date"] if entries else "" latest_version = entries[0]["version"] if entries else "" entries_html = "\n\n".join(render_entry(e) for e in entries) return f"""<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Version history

Version history

{count} releases since {first_date} · latest: {latest_version}

{entries_html}
""" def main(): repo = Path(__file__).resolve().parent.parent.parent src = repo / "changelog.txt" if len(sys.argv) > 1: src = Path(sys.argv[1]) out = repo / "docs" / "changelog" / "index.html" if len(sys.argv) > 2: out = Path(sys.argv[2]) text = src.read_text(encoding="utf-8") entries = parse_changelog(text) html_content = build_html(entries) out.parent.mkdir(parents=True, exist_ok=True) out.write_text(html_content, encoding="utf-8") # Copy favicon files from resources icons_src = repo / "Telegram" / "Resources" / "art" for name in ("icon16.png", "icon32.png"): icon = icons_src / name if icon.exists(): shutil.copy2(icon, out.parent / name) print(f"Generated {out} ({len(entries)} entries, {out.stat().st_size:,} bytes)") if __name__ == "__main__": main() ================================================ FILE: .github/workflows/changelog.yml ================================================ name: Changelog on: push: branches: [dev] paths: [changelog.txt] release: types: [published] workflow_dispatch: permissions: contents: read pages: write id-token: write concurrency: group: pages cancel-in-progress: true jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: "3.12" - name: Generate HTML run: python .github/scripts/generate_changelog.py - name: Upload pages artifact uses: actions/upload-pages-artifact@v4 with: path: docs deploy: needs: build runs-on: ubuntu-latest environment: name: github-pages url: ${{ steps.deploy.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deploy uses: actions/deploy-pages@v4 ================================================ FILE: .github/workflows/docker.yml ================================================ name: Docker. on: push: paths: - '.github/workflows/docker.yml' - 'Telegram/build/docker/centos_env/**' jobs: docker: name: Ubuntu runs-on: ubuntu-latest if: github.ref_name == github.event.repository.default_branch env: IMAGE_TAG: ghcr.io/${{ github.repository }}/centos_env:latest steps: - name: Clone. uses: actions/checkout@v6 with: submodules: recursive - name: First set up. run: | sudo apt update curl -sSL https://install.python-poetry.org | python3 - echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin - name: Free up some disk space. uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be with: tool-cache: true - name: Docker image build. run: | cd Telegram/build/docker/centos_env poetry install DEBUG= LTO= poetry run gen_dockerfile | DOCKER_BUILDKIT=1 docker build -t $IMAGE_TAG - - name: Push the Docker image. run: docker push $IMAGE_TAG ================================================ FILE: .github/workflows/full_source.yml ================================================ name: Upload full source to release. on: release: types: released workflow_dispatch: inputs: release_version: description: 'The version of the release to upload' required: true default: 'v1.0.0' jobs: build: runs-on: ubuntu-latest steps: - name: Clone. uses: actions/checkout@v2 with: submodules: recursive - name: Install prerequisites. run: | pip install git-archive-all if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then # Use the release version from the input if available. p="frk-${{ github.event.inputs.release_version }}-full.tar.gz" else # Otherwise fallback to the release event. p="frk-v${GITHUB_REF##*/v}-full.tar.gz" fi echo "TAG=$p" >> $GITHUB_ENV - name: Build assets. run: | mkdir -p dist/ echo "$TAG" ~/.local/bin/git-archive-all ./dist/${TAG} - name: Get release ID by tag. id: get_release if: github.event_name == 'workflow_dispatch' uses: cardinalby/git-get-release-action@master env: GITHUB_TOKEN: ${{ github.token }} with: tag: ${{ github.event.inputs.release_version }} - name: Set upload URL for release event. id: set_upload_url if: github.event_name == 'release' run: | echo "upload_url=${{ github.event.release.upload_url }}" >> $GITHUB_OUTPUT - name: Upload. uses: lovasoa/upload-release-asset@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url || steps.set_upload_url.outputs.upload_url }} asset_path: ./dist/${{ env.TAG }} asset_label: Source code (tar.gz, full) asset_name: ${{ env.TAG }} asset_content_type: application/x-gzip ================================================ FILE: .github/workflows/inno.yml ================================================ name: Create Inno Setup Installers on: release: types: [released] workflow_dispatch: inputs: version: description: 'Version number (e.g., 1.2.3)' required: true jobs: create-installers: runs-on: windows-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Get version id: version run: | # For workflow_dispatch if (-not [string]::IsNullOrEmpty("${{ github.event.inputs.version }}")) { echo "version=${{ github.event.inputs.version }}" >> $env:GITHUB_OUTPUT echo "version_full=${{ github.event.inputs.version }}" >> $env:GITHUB_OUTPUT } else { # For release event echo "version=$($env:GITHUB_REF -replace 'refs/tags/', '')" >> $env:GITHUB_OUTPUT echo "version_full=$($env:GITHUB_REF -replace 'refs/tags/', '')" >> $env:GITHUB_OUTPUT } shell: pwsh - name: Download x64 zip uses: robinraju/release-downloader@v1.12 with: repository: ${{ github.repository }} tag: ${{ steps.version.outputs.version_full }} fileName: Telegram.zip out-file-path: ./artifacts/x64/ - name: Download x86 zip uses: robinraju/release-downloader@v1.12 with: repository: ${{ github.repository }} tag: ${{ steps.version.outputs.version_full }} fileName: Telegram_x86.zip out-file-path: ./artifacts/x86/ - name: Extract x64 zip run: | Expand-Archive -Path ./artifacts/x64/Telegram.zip -DestinationPath ./artifacts/x64/extracted - name: Extract x86 zip run: | Expand-Archive -Path ./artifacts/x86/Telegram_x86.zip -DestinationPath ./artifacts/x86/extracted - name: Install Inno Setup run: | choco install innosetup -y - name: Prepare directories run: | New-Item -ItemType Directory -Path ./Telegram/build/release_x64 -Force New-Item -ItemType Directory -Path ./Telegram/build/release_x86 -Force Copy-Item -Path ./artifacts/x64/extracted/* -Destination ./Telegram/build/release_x64 -Recurse -Force Copy-Item -Path ./artifacts/x86/extracted/* -Destination ./Telegram/build/release_x86 -Recurse -Force - name: Get release ID by tag. id: get_release if: github.event_name == 'workflow_dispatch' uses: cardinalby/git-get-release-action@master env: GITHUB_TOKEN: ${{ github.token }} with: tag: ${{ github.event.inputs.version }} - name: Set upload URL for release event. id: set_upload_url if: github.event_name == 'release' run: | echo "upload_url=${{ github.event.release.upload_url }}" >> $env:GITHUB_OUTPUT - name: Create x64 installer id: create_x64 run: | $cleanVersion = "${{ steps.version.outputs.version }}".TrimStart('v') echo "Version: $cleanVersion." iscc ./Telegram/build/setup.iss ` /dMyAppVersion=$cleanVersion ` /dMyAppVersionZero=$cleanVersion ` /dMyAppVersionFull=$cleanVersion ` /dMyBuildTarget="win64" ` /dReleasePath="../../artifacts/x64/extracted" ` /dSourcePath="../SourceFiles/" # Find the output exe file $exePath = Get-ChildItem -Path "." -Filter "tsetup-x64.$cleanVersion.exe" -Recurse | Select-Object -First 1 -ExpandProperty FullName if ($exePath) { echo "$exePath" echo "output_file=$exePath" >> $env:GITHUB_OUTPUT } else { Write-Error "Output exe file not found" exit 1 } - name: Create x86 installer id: create_x86 run: | $cleanVersion = "${{ steps.version.outputs.version }}".TrimStart('v') echo "Version: $cleanVersion." iscc ./Telegram/build/setup.iss ` /dMyAppVersion=$cleanVersion ` /dMyAppVersionZero=$cleanVersion ` /dMyAppVersionFull=$cleanVersion ` /dMyBuildTarget="win32" ` /dReleasePath="../../artifacts/x86/extracted" ` /dSourcePath="../SourceFiles/" # Find the output exe file $exePath = Get-ChildItem -Path "." -Filter "tsetup.$cleanVersion.exe" -Recurse | Select-Object -First 1 -ExpandProperty FullName if ($exePath) { echo "$exePath" echo "output_file=$exePath" >> $env:GITHUB_OUTPUT } else { Write-Error "Output exe file not found" exit 1 } - name: Upload x64 installer to release uses: lovasoa/upload-release-asset@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url || steps.set_upload_url.outputs.upload_url }} asset_path: ${{ steps.create_x64.outputs.output_file }} asset_name: Telegram Windows x64 Installer.exe asset_content_type: application/octet-stream - name: Upload x86 installer to release uses: lovasoa/upload-release-asset@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url || steps.set_upload_url.outputs.upload_url }} asset_path: ${{ steps.create_x86.outputs.output_file }} asset_name: Telegram Windows x32 Installer.exe asset_content_type: application/octet-stream ================================================ FILE: .github/workflows/jekyll-gh-pages.yml ================================================ # Sample workflow for building and deploying a Jekyll site to GitHub Pages name: Deploy Jekyll with GitHub Pages dependencies preinstalled on: # Runs on pushes targeting the default branch push: branches: ["dev"] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false jobs: # Build job build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Pages uses: actions/configure-pages@v5 - name: Build with Jekyll uses: actions/jekyll-build-pages@v1 with: source: ./ destination: ./_site jekyll_config: _config_github_pages.yml - name: Upload artifact uses: actions/upload-pages-artifact@v3 # Deployment job deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ================================================ FILE: .github/workflows/linux.yml ================================================ name: Linux. on: workflow_dispatch: inputs: version: description: 'Version label (e.g., v5.15.3)' required: false type: string release: types: [published] repository_dispatch: types: ["Restart linux workflow."] push: paths-ignore: - 'docs/**' - '**.md' - 'changelog.txt' - 'LEGAL' - 'LICENSE' - '.github/**' - '!.github/workflows/linux.yml' - 'snap/**' - 'Telegram/build/**' - '!Telegram/build/docker/centos_env/**' - 'Telegram/Resources/uwp/**' - 'Telegram/Resources/winrc/**' - 'Telegram/SourceFiles/platform/win/**' - 'Telegram/SourceFiles/platform/mac/**' - 'Telegram/Telegram/**' - 'Telegram/configure.bat' - 'Telegram/Telegram.plist' pull_request: paths-ignore: - 'docs/**' - '**.md' - 'changelog.txt' - 'LEGAL' - 'LICENSE' - '.github/**' - '!.github/workflows/linux.yml' - 'snap/**' - 'Telegram/build/**' - '!Telegram/build/docker/centos_env/**' - 'Telegram/Resources/uwp/**' - 'Telegram/Resources/winrc/**' - 'Telegram/SourceFiles/platform/win/**' - 'Telegram/SourceFiles/platform/mac/**' - 'Telegram/Telegram/**' - 'Telegram/configure.bat' - 'Telegram/Telegram.plist' jobs: linux: name: Rocky Linux 8 runs-on: ubuntu-latest strategy: matrix: defines: - "" env: UPLOAD_ARTIFACT: "true" ONLY_CACHE: "false" IMAGE_TAG: tdesktop:centos_env steps: - name: Validate upload secret parts. env: UPDATER_UPLOAD_BASE64: ${{ secrets.UPDATER_UPLOAD_BASE64 }} UPDATER_UPLOAD_BASE64_PART1: ${{ secrets.UPDATER_UPLOAD_BASE64_PART1 }} UPDATER_UPLOAD_BASE64_PART2: ${{ secrets.UPDATER_UPLOAD_BASE64_PART2 }} UPDATER_UPLOAD_BASE64_PART3: ${{ secrets.UPDATER_UPLOAD_BASE64_PART3 }} run: | echo "UPDATER_UPLOAD_BASE64 length: ${#UPDATER_UPLOAD_BASE64}" echo "UPDATER_UPLOAD_BASE64_PART1 length: ${#UPDATER_UPLOAD_BASE64_PART1}" echo "UPDATER_UPLOAD_BASE64_PART2 length: ${#UPDATER_UPLOAD_BASE64_PART2}" echo "UPDATER_UPLOAD_BASE64_PART3 length: ${#UPDATER_UPLOAD_BASE64_PART3}" MERGED_UPLOAD_BASE64="${UPDATER_UPLOAD_BASE64_PART1}${UPDATER_UPLOAD_BASE64_PART2}${UPDATER_UPLOAD_BASE64_PART3}" if [ -z "${MERGED_UPLOAD_BASE64}" ]; then MERGED_UPLOAD_BASE64="${UPDATER_UPLOAD_BASE64}" fi echo "Merged parts length: ${#MERGED_UPLOAD_BASE64}" if [ -z "${MERGED_UPLOAD_BASE64}" ]; then echo "No upload base64 payload provided." exit 0 fi if ! printf "%s" "${MERGED_UPLOAD_BASE64}" | base64 --decode > /tmp/updater_upload_check.zip 2>/tmp/updater_upload_check.err; then echo "Base64 decode failed." cat /tmp/updater_upload_check.err exit 1 fi if [ ! -s /tmp/updater_upload_check.zip ]; then echo "Decoded payload is empty." exit 1 fi echo "Decoded file info: $(file -b /tmp/updater_upload_check.zip)" - name: Clone. uses: actions/checkout@v6 with: submodules: recursive - name: First set up. run: | sudo apt update curl -sSL https://install.python-poetry.org | python3 - cd Telegram/build/docker/centos_env poetry install DOCKERFILE=$(DEBUG= LTO= poetry run gen_dockerfile) echo "$DOCKERFILE" > Dockerfile rm -rf __pycache__ sudo apt -y install wget 7zip unzip cd $GITHUB_WORKSPACE/.. rm -rf DesktopPrivate mkdir -p DesktopPrivate if [ -n "${{ secrets.DESKTOP_PRIVATE_BASE64 }}" ]; then echo "${{ secrets.DESKTOP_PRIVATE_BASE64 }}" | base64 --decode > desktop_private.zip unzip -oq desktop_private.zip -d DesktopPrivate else cd DesktopPrivate echo "#pragma once" > alpha_private.h echo "#pragma once" > packer_private.h echo '${{ secrets.ALPHA_PRIVATE }}' >> alpha_private.h echo '${{ secrets.PACKER_PRIVATE }}' >> packer_private.h cd .. fi wget ${{ secrets.PACK_FILE }} -O p.7z 7za x p.7z -p${{ secrets.PACK_FILE_PASSWORD }} - name: Free up some disk space. uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be with: tool-cache: true - name: Set up Docker Buildx. uses: docker/setup-buildx-action@v4 - name: Libraries cache. uses: actions/cache@v5 with: path: ${{ runner.temp }}/.buildx-cache key: ${{ runner.OS }}-libs-${{ hashFiles('Telegram/build/docker/centos_env/**') }} restore-keys: ${{ runner.OS }}-libs- - name: Libraries. uses: docker/build-push-action@v7 with: context: Telegram/build/docker/centos_env load: ${{ env.ONLY_CACHE == 'false' }} tags: ${{ env.IMAGE_TAG }} cache-from: type=local,src=${{ runner.temp }}/.buildx-cache cache-to: type=local,dest=${{ runner.temp }}/.buildx-cache-new,mode=max - name: Move cache. run: | rm -rf ${{ runner.temp }}/.buildx-cache mv ${{ runner.temp }}/.buildx-cache{-new,} - name: Telegram Desktop build. if: env.ONLY_CACHE == 'false' run: | DEFINE="" if [ -n "${{ matrix.defines }}" ]; then DEFINE="-D ${{ matrix.defines }}=ON" echo Define from matrix: $DEFINE echo "ARTIFACT_NAME=Telegram ${{ matrix.defines }}" >> $GITHUB_ENV else echo "ARTIFACT_NAME=Telegram" >> $GITHUB_ENV fi docker run --rm \ -u $(id -u) \ -v $PWD:/usr/src/tdesktop \ -v $PWD/../DesktopPrivate:/usr/src/DesktopPrivate \ $IMAGE_TAG \ /usr/src/tdesktop/Telegram/build/docker/centos_env/build.sh \ -D TDESKTOP_API_ID=${{ secrets.API_ID }} \ -D TDESKTOP_API_HASH=${{ secrets.API_HASH }} \ -D DESKTOP_APP_SPECIAL_TARGET=linux \ $DEFINE strip -s out/MinSizeRel/Forkgram - name: Check. if: env.ONLY_CACHE == 'false' run: | filePath="out/MinSizeRel/Forkgram" if test -f "$filePath"; then echo "Build successfully done! :)" size=$(stat -c %s "$filePath") echo "File size of ${filePath}: ${size} Bytes." else echo "Build error, output file does not exist." exit 1 fi - name: Compress. if: (github.event_name == 'release') run: tar -cJvf Forkgram.tar.xz -C out/MinSizeRel Forkgram Updater - name: Pack updater files. if: (github.event_name == 'release') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'repository_dispatch') run: | verPacker=$(awk '$1 == "AppVersion" { print $2 }' Telegram/build/version) cd out/MinSizeRel BEFORE=$(mktemp) AFTER=$(mktemp) ls -1 tlinuxupd* 2>/dev/null | sort > "$BEFORE" || true ./Packer -path Forkgram -path Updater -version "$verPacker" ls -1 tlinuxupd* 2>/dev/null | sort > "$AFTER" || true UPDATE_FILE=$(comm -13 "$BEFORE" "$AFTER" | tail -n 1) if [ -z "$UPDATE_FILE" ]; then UPDATE_FILE=$(ls -1t tlinuxupd* | head -n 1) fi if [ -z "$UPDATE_FILE" ] || [ ! -f "$UPDATE_FILE" ]; then echo "Packed update file was not generated." exit 1 fi echo "PACKED_UPDATE_FILE=$GITHUB_WORKSPACE/out/MinSizeRel/$UPDATE_FILE" >> $GITHUB_ENV echo "PACKED_UPDATE_BASENAME=$UPDATE_FILE" >> $GITHUB_ENV echo "VER_PACKER=$verPacker" >> $GITHUB_ENV - name: Upload packed updater to Telegram channel. if: (github.event_name == 'release') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'repository_dispatch') env: UPDATER_UPLOAD_BASE64: ${{ secrets.UPDATER_UPLOAD_BASE64 }} UPDATER_UPLOAD_BASE64_PART1: ${{ secrets.UPDATER_UPLOAD_BASE64_PART1 }} UPDATER_UPLOAD_BASE64_PART2: ${{ secrets.UPDATER_UPLOAD_BASE64_PART2 }} UPDATER_UPLOAD_BASE64_PART3: ${{ secrets.UPDATER_UPLOAD_BASE64_PART3 }} run: | MERGED_UPLOAD_BASE64="${UPDATER_UPLOAD_BASE64_PART1}${UPDATER_UPLOAD_BASE64_PART2}${UPDATER_UPLOAD_BASE64_PART3}" if [ -z "${MERGED_UPLOAD_BASE64}" ]; then MERGED_UPLOAD_BASE64="${UPDATER_UPLOAD_BASE64}" fi if [ -z "${MERGED_UPLOAD_BASE64}" ]; then echo "UPDATER_UPLOAD_BASE64(_PART1/_PART2/_PART3) is empty, skip channel upload." exit 0 fi python3 -m pip install --upgrade pip python3 -m pip install requests tgcrypto-pyrofork Kurigram rm -rf updater_channel_upload mkdir -p updater_channel_upload printf "%s" "${MERGED_UPLOAD_BASE64}" | base64 --decode > updater_upload.raw if unzip -tqq updater_upload.raw >/dev/null 2>&1; then unzip -oq updater_upload.raw -d updater_channel_upload elif tar -tzf updater_upload.raw >/dev/null 2>&1; then tar -xzf updater_upload.raw -C updater_channel_upload elif tar -tf updater_upload.raw >/dev/null 2>&1; then tar -xf updater_upload.raw -C updater_channel_upload else echo "Unsupported upload bundle format: $(file -b updater_upload.raw)" exit 1 fi ( cd updater_channel_upload 7za a -tzip -mx=0 ../updater_upload.zip . >/dev/null ) SCRIPT_PATH=$(find updater_channel_upload -type f -name linux_pack_upl.py | head -n 1) if [ -z "$SCRIPT_PATH" ]; then echo "linux_pack_upl.py not found in UPDATER_UPLOAD_BASE64 bundle." exit 1 fi SCRIPT_DIR=$(dirname "$SCRIPT_PATH") cp "$PACKED_UPDATE_FILE" "$SCRIPT_DIR/" cp updater_upload.zip "$SCRIPT_DIR/" cd "$SCRIPT_DIR" if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt fi python3 linux_pack_upl.py "tlinuxupd${VER_PACKER}" - name: Upload. if: (github.event_name == 'release') uses: svenstaro/upload-release-action@2.11.4 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: ./Forkgram.tar.xz tag: ${{ github.event.release.tag_name }} asset_name: Forkgram.tar.xz ================================================ FILE: .github/workflows/mac.yml ================================================ name: MacOS. on: push: paths-ignore: - 'docs/**' - '**.md' - 'changelog.txt' - 'LEGAL' - 'LICENSE' - '.github/**' - '!.github/workflows/mac.yml' - 'lib/xdg/**' - 'snap/**' - 'Telegram/build/docker/**' - 'Telegram/Resources/uwp/**' - 'Telegram/Resources/winrc/**' - 'Telegram/SourceFiles/platform/win/**' - 'Telegram/SourceFiles/platform/linux/**' - 'Telegram/configure.bat' pull_request: paths-ignore: - 'docs/**' - '**.md' - 'changelog.txt' - 'LEGAL' - 'LICENSE' - '.github/**' - '!.github/workflows/mac.yml' - 'lib/xdg/**' - 'snap/**' - 'Telegram/build/docker/**' - 'Telegram/Resources/uwp/**' - 'Telegram/Resources/winrc/**' - 'Telegram/SourceFiles/platform/win/**' - 'Telegram/SourceFiles/platform/linux/**' - 'Telegram/configure.bat' jobs: macos: name: MacOS runs-on: macos-latest strategy: matrix: defines: - "" env: UPLOAD_ARTIFACT: "true" ONLY_CACHE: "false" PREPARE_PATH: "Telegram/build/prepare/prepare.py" steps: - name: Get repository name. run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV - name: Clone. uses: actions/checkout@v6 with: submodules: recursive path: ${{ env.REPO_NAME }} - name: First set up. run: | sudo chown -R `whoami`:admin /usr/local/share brew update brew upgrade || true brew install automake meson nasm ninja pkg-config # Disable spotlight. sudo mdutil -a -i off sudo xcode-select -s /Applications/Xcode.app/Contents/Developer sudo sed -i '' '/CMAKE_${lang}_FLAGS_DEBUG_INIT/s/ -g//' /opt/homebrew/share/cmake/Modules/Compiler/GNU.cmake - name: Libraries cache. id: cache-libs uses: actions/cache@v5 with: path: | Libraries ThirdParty key: ${{ runner.OS }}-libs-${{ hashFiles(format('{0}/{1}', env.REPO_NAME, env.PREPARE_PATH)) }} restore-keys: ${{ runner.OS }}-libs- - name: Libraries. run: | ./$REPO_NAME/Telegram/build/prepare/mac.sh skip-release silent - name: Free up some disk space. run: find Libraries '(' '(' ! '(' -name '*.a' -o -name '*.h' -o -name '*.hpp' -o -name '*.inc' -o -name '*.cmake' -o -path '*/include/*' -o -path '*/objects-*' -o -path '*/cache_keys/*' -o -path '*/patches/*' -o -perm +111 ')' -type f ')' -o -empty ')' -delete - name: Telegram Desktop build. if: env.ONLY_CACHE == 'false' run: | cd $REPO_NAME/Telegram DEFINE="" if [ -n "${{ matrix.defines }}" ]; then DEFINE="-D ${{ matrix.defines }}=ON" echo Define from matrix: $DEFINE echo "ARTIFACT_NAME=Telegram ${{ matrix.defines }}" >> $GITHUB_ENV else echo "ARTIFACT_NAME=Telegram" >> $GITHUB_ENV fi ./configure.sh \ -D CMAKE_CONFIGURATION_TYPES=Debug \ -D CMAKE_COMPILE_WARNING_AS_ERROR=ON \ -D CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO \ -D TDESKTOP_API_TEST=ON \ -D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF \ -D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF \ $DEFINE cmake --build ../out --config Debug --parallel - name: Move artifact. if: env.UPLOAD_ARTIFACT == 'true' run: | cd $REPO_NAME/out/Debug mkdir artifact mv Telegram.app artifact/ mv Updater artifact/ - uses: actions/upload-artifact@v7 if: env.UPLOAD_ARTIFACT == 'true' name: Upload artifact. with: name: ${{ env.ARTIFACT_NAME }} path: ${{ env.REPO_NAME }}/out/Debug/artifact/ ================================================ FILE: .github/workflows/mac_packaged.yml ================================================ name: MacOS Packaged. on: push: paths-ignore: - 'docs/**' - '**.md' - 'changelog.txt' - 'LEGAL' - 'LICENSE' - '.github/**' - '!.github/workflows/mac_packaged.yml' - 'lib/xdg/**' - 'snap/**' - 'Telegram/build/**' - 'Telegram/Resources/uwp/**' - 'Telegram/Resources/winrc/**' - 'Telegram/SourceFiles/platform/win/**' - 'Telegram/SourceFiles/platform/linux/**' - 'Telegram/configure.bat' pull_request: paths-ignore: - 'docs/**' - '**.md' - 'changelog.txt' - 'LEGAL' - 'LICENSE' - '.github/**' - '!.github/workflows/mac_packaged.yml' - 'lib/xdg/**' - 'snap/**' - 'Telegram/build/**' - 'Telegram/Resources/uwp/**' - 'Telegram/Resources/winrc/**' - 'Telegram/SourceFiles/platform/win/**' - 'Telegram/SourceFiles/platform/linux/**' - 'Telegram/configure.bat' jobs: macos: name: MacOS runs-on: macos-latest strategy: matrix: defines: - "" env: GIT: "https://github.com" CMAKE_GENERATOR: "Ninja" CMAKE_BUILD_TYPE: "Debug" CMAKE_BUILD_PARALLEL_LEVEL: "" CMAKE_PREFIX_PATH: "/opt/homebrew/opt/ffmpeg@6:/opt/homebrew/opt/openal-soft" TDE2E: "51743dfd01dff6179e2d8f7095729caa4e2222e9" UPLOAD_ARTIFACT: "true" ONLY_CACHE: "false" MANUAL_CACHING: "1" AUTO_CACHING: "1" steps: - name: Get repository name. run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV - name: Clone. uses: actions/checkout@v6 with: submodules: recursive path: ${{ env.REPO_NAME }} - name: First set up. run: | brew update brew upgrade || true brew install ada-url autoconf automake boost cmake ffmpeg@6 jpeg-xl libavif libheif libtool openal-soft openh264 openssl opus ninja pkg-config python qtbase qtimageformats qtsvg xz || true sudo xcode-select -s /Applications/Xcode.app/Contents/Developer sudo sed -i '' '/CMAKE_${lang}_FLAGS_DEBUG_INIT/s/ -g//' /opt/homebrew/share/cmake/Modules/Compiler/GNU.cmake xcodebuild -version > CACHE_KEY.txt brew list --versions >> CACHE_KEY.txt echo $MANUAL_CACHING >> CACHE_KEY.txt echo "$GITHUB_WORKSPACE" >> CACHE_KEY.txt if [ "$AUTO_CACHING" = "1" ]; then thisFile=$REPO_NAME/.github/workflows/mac_packaged.yml echo `md5 -q $thisFile` >> CACHE_KEY.txt fi echo "CACHE_KEY=`md5 -q CACHE_KEY.txt`" >> $GITHUB_ENV echo "MACOSX_DEPLOYMENT_TARGET=$(grep 'set(QT_SUPPORTED_MIN_MACOS_VERSION' /opt/homebrew/Cellar/qtbase/*/lib/cmake/Qt6/Qt6ConfigExtras.cmake | sed -E 's/^.*"(.*)"\)$/\1/')" >> $GITHUB_ENV echo "LibrariesPath=`pwd`" >> $GITHUB_ENV echo "RNNOISE=`curl -sSL --header 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' https://api.github.com/repos/xiph/rnnoise/git/refs/heads/master | jq -r .object.sha`" >> $GITHUB_ENV echo "WEBRTC=`curl -sSL --header 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master | jq -r .object.sha`" >> $GITHUB_ENV - name: RNNoise cache. id: cache-rnnoise uses: actions/cache@v5 with: path: ${{ env.LibrariesPath }}/local/rnnoise key: ${{ runner.OS }}-rnnoise-${{ env.RNNOISE }}-${{ env.CACHE_KEY }} - name: RNNoise. if: steps.cache-rnnoise.outputs.cache-hit != 'true' run: | cd $LibrariesPath git clone --depth=1 $GIT/xiph/rnnoise.git cd rnnoise ./autogen.sh ./configure --prefix=$LibrariesPath/local/rnnoise --disable-examples --disable-doc make -j$(sysctl -n hw.logicalcpu) make install - name: WebRTC cache. id: cache-webrtc uses: actions/cache@v5 with: path: ${{ env.LibrariesPath }}/local/tg_owt key: ${{ runner.OS }}-webrtc-${{ env.WEBRTC }}-${{ env.CACHE_KEY }} - name: WebRTC. if: steps.cache-webrtc.outputs.cache-hit != 'true' run: | cd $LibrariesPath git clone --depth=1 --recursive --shallow-submodules $GIT/desktop-app/tg_owt.git cd tg_owt cmake -Bbuild . -DCMAKE_INSTALL_PREFIX=$LibrariesPath/local/tg_owt cmake --build build cmake --install build - name: TDE2E cache. id: cache-tde2e uses: actions/cache@v5 with: path: ${{ env.LibrariesPath }}/local/tde2e key: ${{ runner.OS }}-tde2e-${{ env.TDE2E }}-${{ env.CACHE_KEY }} - name: TDE2E. if: steps.cache-tde2e.outputs.cache-hit != 'true' run: | cd $LibrariesPath git init tde2e cd tde2e git remote add origin $GIT/tdlib/td.git git fetch --depth=1 origin $TDE2E git reset --hard FETCH_HEAD cmake -Bbuild . -DCMAKE_INSTALL_PREFIX=$LibrariesPath/local/tde2e -DTD_E2E_ONLY=ON cmake --build build cmake --install build - name: Telegram Desktop build. if: env.ONLY_CACHE == 'false' run: | cd $REPO_NAME export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH$(find $LibrariesPath/local -mindepth 1 -maxdepth 1 -type d -exec printf ':%s' {} +)" DEFINE="" if [ -n "${{ matrix.defines }}" ]; then DEFINE="-D ${{ matrix.defines }}=ON" echo Define from matrix: $DEFINE echo "ARTIFACT_NAME=Telegram ${{ matrix.defines }}" >> $GITHUB_ENV else echo "ARTIFACT_NAME=Telegram" >> $GITHUB_ENV fi cmake -Bbuild . -DTDESKTOP_API_TEST=ON $DEFINE cmake --build build macdeployqt build/Telegram.app codesign --remove-signature build/Telegram.app - name: Move artifact. if: env.UPLOAD_ARTIFACT == 'true' run: | cd $REPO_NAME/build mkdir artifact mv Telegram.app artifact/ - uses: actions/upload-artifact@v7 if: env.UPLOAD_ARTIFACT == 'true' name: Upload artifact. with: name: ${{ env.ARTIFACT_NAME }} path: ${{ env.REPO_NAME }}/build/artifact/ ================================================ FILE: .github/workflows/needs-user-action.yml ================================================ name: Needs user action. on: issue_comment: types: [created] schedule: - cron: '0 2 * * *' jobs: needs-user-action: runs-on: ubuntu-slim steps: - uses: lee-dohm/no-response@v0.5.0 with: token: ${{ github.token }} responseRequiredLabel: needs user action ================================================ FILE: .github/workflows/snap.yml ================================================ name: Snap on: release: types: [published] workflow_dispatch: jobs: snap: name: Build and publish snap runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 submodules: recursive - name: Setup LXD run: | sudo iptables -P FORWARD ACCEPT sudo snap install --classic snapcraft sudo usermod -aG lxd $USER sudo lxd init --auto sudo lxd waitready - name: Free up disk space uses: samueldr/more-space-action@97048bd0df83fb05b5257887bdbaffc848887673 with: enable-remove-default-apt-patterns: false enable-lvm-span: true lvm-span-mountpoint: /var/snap/lxd/common/lxd/storage-pools/default/containers - name: Build snap run: sudo -u $USER snap run snapcraft --verbosity=debug - name: Find snap artifact run: | SNAP_FILE=$(echo forkgram_*.snap) echo "SNAP_FILE=$SNAP_FILE" >> "$GITHUB_ENV" - name: Upload artifact uses: actions/upload-artifact@v7 with: name: ${{ env.SNAP_FILE }} path: ${{ env.SNAP_FILE }} - name: Publish to Snap Store env: SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }} run: snapcraft upload "$SNAP_FILE" --release=stable ================================================ FILE: .github/workflows/waiting-for-answer.yml ================================================ name: Waiting for answer. on: issue_comment: types: [created] schedule: - cron: '30 0 * * *' jobs: waiting-for-answer: runs-on: ubuntu-slim steps: - uses: lee-dohm/no-response@v0.5.0 with: token: ${{ github.token }} responseRequiredLabel: waiting for answer ================================================ FILE: .github/workflows/win.yml ================================================ name: Windows. on: push: paths-ignore: - 'docs/**' - '**.md' - '!docs/building-win*.md' - 'changelog.txt' - 'LEGAL' - 'LICENSE' - '.github/**' - '!.github/workflows/win.yml' - 'lib/xdg/**' - 'snap/**' - 'Telegram/build/docker/**' - 'Telegram/Resources/uwp/**' - 'Telegram/SourceFiles/platform/linux/**' - 'Telegram/SourceFiles/platform/mac/**' - 'Telegram/Telegram/**' - 'Telegram/configure.sh' - 'Telegram/Telegram.plist' pull_request: paths-ignore: - 'docs/**' - '**.md' - '!docs/building-win*.md' - 'changelog.txt' - 'LEGAL' - 'LICENSE' - '.github/**' - '!.github/workflows/win.yml' - 'lib/xdg/**' - 'snap/**' - 'Telegram/build/docker/**' - 'Telegram/Resources/uwp/**' - 'Telegram/SourceFiles/platform/linux/**' - 'Telegram/SourceFiles/platform/mac/**' - 'Telegram/Telegram/**' - 'Telegram/configure.sh' - 'Telegram/Telegram.plist' jobs: windows: name: Windows runs-on: ${{ matrix.arch == 'arm64' && 'windows-11-arm' || 'windows-latest' }} strategy: matrix: arch: [x64_x86, x64, arm64] qt: ["", qt6] generator: ["", "Ninja Multi-Config"] exclude: - arch: arm64 qt: "" - arch: x64_x86 qt: qt6 env: UPLOAD_ARTIFACT: "true" ONLY_CACHE: "false" PREPARE_PATH: "Telegram/build/prepare/prepare.py" defaults: run: shell: cmd steps: - name: Prepare directories. run: | mkdir %userprofile%\TBuild\Libraries mklink /d %GITHUB_WORKSPACE%\TBuild %userprofile%\TBuild echo TBUILD=%GITHUB_WORKSPACE%\TBuild>>%GITHUB_ENV% echo LibrariesPath=%GITHUB_WORKSPACE%\TBuild\Libraries${{ matrix.arch == 'x64' && '\win64' || '' }}>>%GITHUB_ENV% - name: Get repository name. shell: bash run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV - name: Clone. uses: actions/checkout@v6 with: submodules: recursive path: ${{ env.TBUILD }}\${{ env.REPO_NAME }} - name: First set up. shell: bash run: | DOCPATH=$TBUILD/$REPO_NAME/docs/building-win.md SDK="$(grep "SDK version" $DOCPATH | sed -r 's/.*\*\*(.*)\*\* SDK version.*/\1/')" echo "SDK=$SDK" >> $GITHUB_ENV sed -i '/CMAKE_${lang}_FLAGS_DEBUG_INIT/s/${_Zi}//' "$PROGRAMFILES"/CMake/share/cmake*/Modules/Platform/Windows-MSVC.cmake echo "$(sha256sum $TBUILD/$REPO_NAME/$PREPARE_PATH | awk '{ print $1 }')" >> CACHE_KEY.txt echo "$SDK" >> CACHE_KEY.txt echo "CACHE_KEY=$(sha256sum CACHE_KEY.txt | awk '{ print $1 }')" >> $GITHUB_ENV echo "Configurate git for cherry-picks." git config --global user.email "you@example.com" git config --global user.name "Sample" - uses: ilammy/msvc-dev-cmd@v1.13.0 name: Native Tools Command Prompt. with: arch: ${{ matrix.arch }} sdk: ${{ env.SDK }} - name: NuGet sources. run: | nuget sources Disable -Name "Microsoft Visual Studio Offline Packages" nuget sources Add -Source https://api.nuget.org/v3/index.json & exit 0 - name: ThirdParty cache. id: cache-third-party uses: actions/cache@v5 with: path: ${{ env.TBUILD }}\ThirdParty key: ${{ runner.OS }}-${{ runner.arch }}-third-party-${{ env.CACHE_KEY }} restore-keys: ${{ runner.OS }}-${{ runner.arch }}-third-party- - name: Libraries cache. id: cache-libs uses: actions/cache@v5 with: path: | ${{ env.LibrariesPath }}\* !${{ env.LibrariesPath }}\cache_keys !${{ env.LibrariesPath }}\[qQ]t[_-]* ${{ env.LibrariesPath }}\cache_keys\* !${{ env.LibrariesPath }}\cache_keys\[qQ]t[_-]* key: ${{ runner.OS }}-${{ matrix.arch }}-libs-${{ env.CACHE_KEY }} restore-keys: ${{ runner.OS }}-${{ matrix.arch }}-libs- - name: Qt cache. id: cache-qt uses: actions/cache@v5 with: path: | ${{ env.LibrariesPath }}\[qQ]t[_-]* ${{ env.LibrariesPath }}\cache_keys\[qQ]t[_-]* key: ${{ runner.OS }}-${{ matrix.arch }}-${{ matrix.qt || 'qt' }}-${{ env.CACHE_KEY }} restore-keys: ${{ runner.OS }}-${{ matrix.arch }}-${{ matrix.qt || 'qt' }}- - name: Libraries. env: GYP_MSVS_OVERRIDE_PATH: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\' GYP_MSVS_VERSION: 2022 run: | %TBUILD%\%REPO_NAME%\Telegram\build\prepare\win.bat skip-release silent ${{ matrix.qt }} - name: Read configuration matrix. shell: bash run: | ARTIFACT_NAME="Telegram" ARCH="" if [ -n "${{ matrix.arch }}" ]; then case "${{ matrix.arch }}" in x64_x86) ARCH="x86";; arm64) ARCH="arm";; *) ARCH="${{ matrix.arch }}";; esac echo "Architecture from matrix: $ARCH" ARTIFACT_NAME="${ARTIFACT_NAME} ${{ matrix.arch }}" fi if [ -n "${{ matrix.qt }}" ]; then ARTIFACT_NAME="${ARTIFACT_NAME} ${{ matrix.qt }}" fi GENERATOR="" if [ -n "${{ matrix.generator }}" ]; then GENERATOR="-G \"${{ matrix.generator }}\"" echo "Generator from matrix: $GENERATOR" ARTIFACT_NAME="${ARTIFACT_NAME} ${{ matrix.generator }}" fi echo "TDESKTOP_BUILD_GENERATOR=$GENERATOR" >> $GITHUB_ENV [ -n "$GENERATOR" ] && ARCH="" echo "TDESKTOP_BUILD_ARCH=$ARCH" >> $GITHUB_ENV DEFINE="" if [ -n "${{ matrix.defines }}" ]; then DEFINE="-D ${{ matrix.defines }}=ON" echo "Define from matrix: $DEFINE" ARTIFACT_NAME="${ARTIFACT_NAME} ${{ matrix.defines }}" fi echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV API="-D TDESKTOP_API_TEST=ON" if [ $GITHUB_REF == 'refs/heads/nightly' ]; then echo "Use the open credentials." API="-D TDESKTOP_API_ID=611335 -D TDESKTOP_API_HASH=d524b414d21f4d37f08684c1df41ac9c" fi echo "TDESKTOP_BUILD_API=$API" >> $GITHUB_ENV - name: Free up some disk space. shell: bash run: find $LibrariesPath '(' '(' ! '(' -name '*.lib' -o -name '*.a' -o -name '*.exe' -o -name '*.h' -o -name '*.hpp' -o -name '*.inc' -o -name '*.cmake' -o -path '*/include/*' -o -path '*/objects-*' -o -path '*/cache_keys/*' -o -path '*/patches/*' ')' -type f ')' -o -empty ')' -delete - name: Telegram Desktop build. if: env.ONLY_CACHE == 'false' run: | cd %TBUILD%\%REPO_NAME%\Telegram call configure.bat ^ %TDESKTOP_BUILD_GENERATOR% ^ %TDESKTOP_BUILD_ARCH% ^ ${{ matrix.qt }} ^ %TDESKTOP_BUILD_API% ^ -D CMAKE_CONFIGURATION_TYPES=Debug ^ -D CMAKE_COMPILE_WARNING_AS_ERROR=ON ^ -D CMAKE_MSVC_DEBUG_INFORMATION_FORMAT= ^ -D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF ^ -D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF ^ %TDESKTOP_BUILD_DEFINE% cmake --build ..\out --config Debug --parallel - name: Move artifact. if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly') run: | set OUT=%TBUILD%\%REPO_NAME%\out\Debug mkdir artifact move %OUT%\Telegram.exe artifact/ move %OUT%\Updater.exe artifact/ - uses: actions/upload-artifact@v7 name: Upload artifact. if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly') with: name: ${{ env.ARTIFACT_NAME }} path: artifact\ ================================================ FILE: .gitignore ================================================ /out/ Debug/ Release/ /ThirdParty/ /Telegram/build/target /Telegram/tests/ /Telegram/gyp/tests/*.test /Telegram/out/ /Telegram/*.user *.vcxproj* *.sln *.suo *.sdf *.opensdf *.opendb *.VC.db *.aps *.xcodeproj ipch/ .vs/ .vscode/ .cache/ compile_commands.json /Telegram/log.txt /Telegram/data /Telegram/data_config /Telegram/DebugLogs/ /Telegram/tdata/ /Telegram/tdumps/ .DS_Store ._* .qmake.stash /Mac/ project.xcworkspace xcuserdata parts prime stage *.snap .snapcraft /snap/gui/*.png /snap/gui/*.desktop /snap/plugins/__pycache__ /Telegram/*.user.* *.txt.user *.pro.user /Linux/ /Telegram/Makefile *.*~ .idea/ cmake-build-debug/ *.qsb # Local configuration files settings.local.json *.local.json .env .env.local .env.*.local # Cursor IDE local settings (but keep .cursor/rules/) .cursor/* !.cursor/rules/ # AI work folder (session-specific, not for version control) .ai # Generated changelog page (built by CI, deployed to GitHub Pages) /docs/changelog/ ================================================ FILE: .gitmodules ================================================ [submodule "Telegram/ThirdParty/GSL"] path = Telegram/ThirdParty/GSL url = https://github.com/Microsoft/GSL.git [submodule "Telegram/ThirdParty/xxHash"] path = Telegram/ThirdParty/xxHash url = https://github.com/Cyan4973/xxHash.git [submodule "Telegram/ThirdParty/rlottie"] path = Telegram/ThirdParty/rlottie url = https://github.com/desktop-app/rlottie.git [submodule "Telegram/ThirdParty/lz4"] path = Telegram/ThirdParty/lz4 url = https://github.com/lz4/lz4.git [submodule "Telegram/lib_crl"] path = Telegram/lib_crl url = https://github.com/desktop-app/lib_crl.git [submodule "Telegram/lib_rpl"] path = Telegram/lib_rpl url = https://github.com/desktop-app/lib_rpl.git [submodule "Telegram/lib_base"] path = Telegram/lib_base url = https://github.com/desktop-app/lib_base.git [submodule "Telegram/codegen"] path = Telegram/codegen url = https://github.com/forkgram/codegen.git [submodule "Telegram/lib_ui"] path = Telegram/lib_ui url = https://github.com/forkgram/lib_ui.git [submodule "Telegram/lib_lottie"] path = Telegram/lib_lottie url = https://github.com/desktop-app/lib_lottie.git [submodule "Telegram/lib_tl"] path = Telegram/lib_tl url = https://github.com/desktop-app/lib_tl.git [submodule "Telegram/lib_spellcheck"] path = Telegram/lib_spellcheck url = https://github.com/desktop-app/lib_spellcheck [submodule "Telegram/lib_storage"] path = Telegram/lib_storage url = https://github.com/desktop-app/lib_storage.git [submodule "cmake"] path = cmake url = https://github.com/desktop-app/cmake_helpers.git [submodule "Telegram/ThirdParty/expected"] path = Telegram/ThirdParty/expected url = https://github.com/TartanLlama/expected [submodule "Telegram/ThirdParty/QR"] path = Telegram/ThirdParty/QR url = https://github.com/nayuki/QR-Code-generator [submodule "Telegram/lib_qr"] path = Telegram/lib_qr url = https://github.com/desktop-app/lib_qr.git [submodule "Telegram/ThirdParty/hunspell"] path = Telegram/ThirdParty/hunspell url = https://github.com/hunspell/hunspell [submodule "Telegram/ThirdParty/range-v3"] path = Telegram/ThirdParty/range-v3 url = https://github.com/ericniebler/range-v3.git [submodule "Telegram/ThirdParty/nimf"] path = Telegram/ThirdParty/nimf url = https://github.com/hamonikr/nimf.git [submodule "Telegram/ThirdParty/hime"] path = Telegram/ThirdParty/hime url = https://github.com/hime-ime/hime.git [submodule "Telegram/ThirdParty/fcitx5-qt"] path = Telegram/ThirdParty/fcitx5-qt url = https://github.com/fcitx/fcitx5-qt.git [submodule "Telegram/lib_webrtc"] path = Telegram/lib_webrtc url = https://github.com/desktop-app/lib_webrtc.git [submodule "Telegram/ThirdParty/tgcalls"] path = Telegram/ThirdParty/tgcalls url = https://github.com/TelegramMessenger/tgcalls.git [submodule "Telegram/lib_webview"] path = Telegram/lib_webview url = https://github.com/desktop-app/lib_webview.git [submodule "Telegram/ThirdParty/dispatch"] path = Telegram/ThirdParty/dispatch url = https://github.com/apple/swift-corelibs-libdispatch [submodule "Telegram/ThirdParty/kimageformats"] path = Telegram/ThirdParty/kimageformats url = https://github.com/KDE/kimageformats.git [submodule "Telegram/ThirdParty/kcoreaddons"] path = Telegram/ThirdParty/kcoreaddons url = https://github.com/KDE/kcoreaddons.git [submodule "Telegram/ThirdParty/cld3"] path = Telegram/ThirdParty/cld3 url = https://github.com/google/cld3.git [submodule "Telegram/ThirdParty/libprisma"] path = Telegram/ThirdParty/libprisma url = https://github.com/desktop-app/libprisma.git [submodule "Telegram/ThirdParty/xdg-desktop-portal"] path = Telegram/ThirdParty/xdg-desktop-portal url = https://github.com/flatpak/xdg-desktop-portal.git [submodule "Telegram/lib_translate"] path = Telegram/lib_translate url = https://github.com/desktop-app/lib_translate [submodule "Telegram/ThirdParty/zbar"] path = Telegram/ThirdParty/zbar url = https://github.com/mchehab/zbar.git ================================================ FILE: AGENTS.md ================================================ # Agent Guide for Telegram Desktop This guide defines repository-wide instructions for coding agents working with the Telegram Desktop codebase. ## Build System Structure The build system expects this directory layout: ```text L:\Telegram\ # BuildPath L:\Telegram\tdesktop\ # Repository (you work here) L:\Telegram\Libraries\ # 32-bit dependencies (Linux/macOS) L:\Telegram\win64\Libraries\ # 64-bit dependencies (Windows) L:\Telegram\ThirdParty\ # Build tools (NuGet, Python, etc.) ``` Dependencies are located relative to the repository: `../Libraries`, `../win64/Libraries`, or `../ThirdParty`. ## Build Configuration ### Build Commands **From repository root, run:** ```bash cmake --build out --config Debug --target Telegram ``` That's it. The `out/` directory is already configured. The executable will be at `out/Debug/Telegram.exe`. **Important:** When running cmake from a shell that doesn't support `cd`, use quoted absolute paths: ```bash cmake --build "l:\Telegram\tx64\out" --config Debug --target Telegram ``` **Never build Release** - it's extremely heavy and not needed for testing changes. ## Platform-Specific Requirements ### Windows - Requires Visual Studio 2022 - Must run from appropriate Native Tools Command Prompt: - "x64 Native Tools Command Prompt" for `win64` - "x86 Native Tools Command Prompt" for `win` - "ARM64 Native Tools Command Prompt" for `winarm` - Dependencies: `../win64/Libraries` (64-bit) or `../Libraries` (32-bit) ### macOS - Requires Xcode - Dependencies: `../Libraries/local/Qt-*` - Set `QT` environment variable: `export QT=6.8` ### Linux - Build dependencies in `../Libraries` - Set `QT` environment variable if needed ## Key Files - **`Telegram/build/version`** - Version information - **`out/`** - Build output directory ## Troubleshooting ### "Libraries not found" Ensure the repository is in `L:\Telegram\tdesktop`. The build system requires `../win64/Libraries` to exist. ### Build fails with "wrong command prompt" On Windows, use the correct Visual Studio Native Tools Command Prompt matching your target (x64/x86/ARM64). ### Build fails with PDB or EXE access errors **⚠️ CRITICAL: DO NOT RETRY THE BUILD. STOP AND WAIT FOR USER.** If the build fails with ANY of these errors: - `fatal error C1041: cannot open program database` - `cannot open output file 'Telegram.exe'` - `LNK1104: cannot open file` - Any "access denied" or "file in use" error **STOP IMMEDIATELY.** These errors mean files are locked by a running process (Telegram.exe or debugger). **What to do:** 1. Do NOT attempt another build - it will fail the same way 2. Do NOT try to delete files - they are locked 3. Do NOT try any workarounds or fixes 4. IMMEDIATELY inform the user: > "Build failed - files are locked. Please close Telegram.exe (and any debugger) so I can rebuild." **Then WAIT for user confirmation before attempting any build.** Retrying builds wastes time and context. The ONLY fix is for the user to close the running process. ## Best Practices 1. **Always use Debug builds** - Release builds are extremely heavy 2. **Don't build Release configuration** - it's too heavy for testing ## Text File Format - On Windows, keep project text files with CRLF line endings. - Do not save source, header, build/config, style, or localization files as UTF-8 with BOM. Use UTF-8 without BOM. - When rewriting project text files for normalization, preserve file content otherwise and do not introduce a BOM. ## Local Storage Serialization Both app-level (`Core::Settings`) and session-level (`Main::SessionSettings`) use sequential binary serialization via `QDataStream`. Key rules: - New fields must ALWAYS be appended at the **end** of the stream, never inserted in the middle - Reading new fields must be guarded with `!stream.atEnd()` and provide a meaningful default/fallback - Inserting in the middle breaks reading of data saved by older versions (the new read code consumes bytes that belong to subsequent fields) - For simple flags and values, prefer using the generic KV prefs facility (`writePref` / `readPref`) instead of adding to the binary stream -- this avoids serialization ordering issues entirely --- # Development Guidelines ## Coding Style **Do NOT write comments in code:** This is important! Do not write single-line comments that describe what the next line does - they are bloat. Comments are allowed ONLY to describe complex algorithms in detail, when the explanation requires at least 4-5 lines. Self-documenting code with clear variable and function names is preferred. ```cpp // BAD - don't do this: // Get the user's name auto name = user->name(); // Check if premium if (user->isPremium()) { // GOOD - no comments needed, code is self-explanatory: auto name = user->name(); if (user->isPremium()) { // ACCEPTABLE - complex algorithm explanation (4+ lines): // The algorithm works by first collecting all visible messages // in the viewport, then calculating their intersection with // the clip rectangle. Messages are grouped by date headers, // and we need to account for sticky headers that may overlap // with the first message in each group. ``` **Style and formatting rules** are in `REVIEW.md` — see that file for empty-line-before-closing-brace, operator placement in multi-line expressions, if-with-initializer, and other mechanical style rules. **Use `auto` for type deduction:** Prefer `auto` (or `const auto`, `const auto &`) instead of explicit types: ```cpp // Prefer this: auto currentTitle = tr::lng_settings_title(tr::now); auto nameProducer = GetNameProducer(); // Instead of this: QString currentTitle = tr::lng_settings_title(tr::now); rpl::producer nameProducer = GetNameProducer(); ``` ## API Usage ### API Schema Files API definitions use [TL Language](https://core.telegram.org/mtproto/TL): 1. **`Telegram/SourceFiles/mtproto/scheme/mtproto.tl`** - MTProto protocol (encryption, auth, etc.) 2. **`Telegram/SourceFiles/mtproto/scheme/api.tl`** - Telegram API (messages, users, chats, etc.) ### Making API Requests Standard pattern using `api()`, generated `MTP...` types, and callbacks: ```cpp api().request(MTPnamespace_MethodName( MTP_flags(flags_value), MTP_inputPeer(peer), MTP_string(messageText), MTP_long(randomId), MTP_vector() )).done([=](const MTPResponseType &result) { // Handle successful response // Multiple constructors - use .match() or check type: result.match([&](const MTPDuser &data) { // use data.vfirst_name().v }, [&](const MTPDuserEmpty &data) { // handle empty user }); // Single constructor - use .data() shortcut: const auto &data = result.data(); // use data.vmessages().v }).fail([=](const MTP::Error &error) { // Handle API error if (error.type() == u"FLOOD_WAIT_X"_q) { // Handle flood wait } }).handleFloodErrors().send(); ``` **Key points:** - Always refer to `api.tl` for method signatures and return types - Use generated `MTP...` types for parameters (`MTP_int`, `MTP_string`, etc.) - For multiple constructors, use `.match()` or check `.type()` against `mtpc_` constants then call `.c_constructorName()`: ```cpp // Using match: result.match([&](const MTPDuser &data) { ... }, [&](const MTPDuserEmpty &data) { ... }); // Or explicit type check: if (result.type() == mtpc_user) { const auto &data = result.c_user(); // asserts on type mismatch } ``` - For single constructors, use `.data()` shortcut - Include `.handleFloodErrors()` before `.send()` in rare cases where you want special case flood error handling ## UI Styling ### Style Files UI styles are defined in `.style` files using custom syntax: ```style using "ui/basic.style"; using "ui/widgets/widgets.style"; MyButtonStyle { textPadding: margins; icon: icon; height: pixels; } defaultButton: MyButtonStyle { textPadding: margins(10px, 15px, 10px, 15px); icon: icon{{ "gui/icons/search", iconColor }}; height: 30px; } primaryButton: MyButtonStyle(defaultButton) { icon: icon{{ "gui/icons/check", iconColor }}; } ``` **Built-in types:** - `int` - Integer numbers (e.g., `maxLines: 3;`) - `bool` - Boolean values (e.g., `useShadow: true;`) - `pixels` - Pixel values with `px` suffix (e.g., `10px`) - `color` - Named colors from `ui/colors.palette` - `icon` - Inline icon definition: `icon{{ "path/stem", color }}` - `margins` - Four values: `margins(top, right, bottom, left)` - `size` - Two values: `size(width, height)` - `point` - Two values: `point(x, y)` - `align` - Alignment: `align(center)`, `align(left)` - `font` - Font: `font(14px semibold)` - `double` - Floating point **Multi-part icons** (layers drawn bottom-up): ```style myComplexIcon: icon{ { "gui/icons/background", iconBgColor }, { "gui/icons/foreground", iconFgColor } }; ``` **Borders** are typically separate fields, not a single property: ```style chatInput { border: 1px; // width borderFg: defaultInputFieldBorder; // color } ``` **Never hardcode sizes in code:** The app supports different interface scale options. Style `px` values are automatically scaled at runtime, but raw integer constants in code are not. Never use hardcoded numbers for margins, paddings, spacing, sizes, coordinates, or any other dimensional values. Always define them in `.style` files and reference via `st::`. ```cpp // BAD - breaks at non-100% interface scale: p.drawText(10, 20, text); widget->setFixedHeight(48); auto margin = 8; auto iconSize = QSize(24, 24); // GOOD - define in .style file and reference: p.drawText(st::myWidgetTextLeft, st::myWidgetTextTop, text); widget->setFixedHeight(st::myWidgetHeight); auto margin = st::myWidgetMargin; auto iconSize = st::myWidgetIconSize; ``` **Duration constants**: Animation durations should NOT go in `.style` files, this is a legacy approach. Prefer `constexpr auto kName = crl::time(N)` in an anonymous namespace in the relevant `.cpp` file. ### Usage in Code ```cpp #include "styles/style_widgets.h" // Access style members int height = st::primaryButton.height; const style::icon &icon = st::primaryButton.icon; style::margins padding = st::primaryButton.textPadding; // Use in painting void MyWidget::paintEvent(QPaintEvent *e) { Painter p(this); p.fillRect(rect(), st::chatInput.backgroundColor); } ``` ## Localization ### String Definitions Strings are defined in `Telegram/Resources/langs/lang.strings`: ``` "lng_settings_title" = "Settings"; "lng_confirm_delete_item" = "Are you sure you want to delete {item_name}?"; "lng_files_selected#one" = "{count} file selected"; "lng_files_selected#other" = "{count} files selected"; ``` ### Usage in Code **Immediate (current value):** ```cpp auto currentTitle = tr::lng_settings_title(tr::now); auto currentConfirmation = tr::lng_confirm_delete_item( tr::now, lt_item_name, currentItemName); auto filesText = tr::lng_files_selected(tr::now, lt_count, count); ``` **Reactive (rpl::producer):** ```cpp auto titleProducer = tr::lng_settings_title(); auto confirmationProducer = tr::lng_confirm_delete_item( lt_item_name, std::move(itemNameProducer)); auto filesTextProducer = tr::lng_files_selected( lt_count, countProducer | tr::to_count()); ``` **Key points:** - Pass `tr::now` as first argument for immediate `QString` - Omit `tr::now` for reactive `rpl::producer` - Placeholders use `lt_tag_name, value` pattern - For `{count}`: immediate uses `int`, reactive uses `rpl::producer` with `| tr::to_count()` - Move producers with `std::move` when passing to placeholders - Rich text projectors — these `tr::` helpers serve double duty: as the **last argument** (projector) they set the return type to `TextWithEntities`, and as **placeholder values** they wrap individual substitutions in formatting. Always prefer them over `Ui::Text::Bold()`, `Ui::Text::RichLangValue`, etc. — see REVIEW.md for the full mapping. - `tr::marked` — basic projection, converts `QString` to `TextWithEntities` - `tr::rich` — interprets `**bold**`/`__italic__` markup in the string - `tr::bold`, `tr::italic`, `tr::underline` — wrap text in that formatting - `tr::link` — wrap as a clickable link - `tr::url(u"https://..."_q)` — returns a projection that converts text to a link pointing to the given URL; can be passed to `rpl::map` or directly to a `tr::lng_...` call ```cpp // As last argument (projector): auto title = tr::lng_export_progress_title(tr::now, tr::bold); auto text = tr::lng_proxy_incorrect_secret(tr::now, tr::rich); // As placeholder value wrapper + projector: auto desc = tr::lng_some_key( tr::now, lt_name, tr::bold(userName), lt_group, tr::bold(groupName), tr::rich); // Nested tr::lng as placeholder: auto linked = tr::lng_settings_birthday_contacts( lt_link, tr::lng_settings_birthday_contacts_link(tr::url(link)), tr::marked); ``` ## RPL (Reactive Programming Library) ### Core Concepts **Producers** represent streams of values over time: ```cpp auto intProducer = rpl::single(123); // Emits single value auto lifetime = rpl::lifetime(); // Manages subscription lifetime ``` ### Starting Pipelines ```cpp std::move(counter) | rpl::on_next([=](int value) { qDebug() << "Received: " << value; }, lifetime); // Without lifetime parameter - MUST store returned lifetime: auto subscriptionLifetime = std::move(counter) | rpl::on_next([=](int value) { // process value }); ``` ### Transforming Producers ```cpp auto strings = std::move(ints) | rpl::map([](int value) { return QString::number(value * 2); }); auto evenInts = std::move(ints) | rpl::filter([](int value) { return (value % 2 == 0); }); ``` ### Combining Producers **`rpl::combine`** - combines latest values (lambdas receive unpacked arguments): ```cpp auto combined = rpl::combine(countProducer, textProducer); std::move(combined) | rpl::on_next([=](int count, const QString &text) { qDebug() << "Count=" << count << ", Text=" << text; }, lifetime); ``` **`rpl::merge`** - merges producers of same type: ```cpp auto merged = rpl::merge(sourceA, sourceB); std::move(merged) | rpl::on_next([=](QString &&value) { qDebug() << "Merged value: " << value; }, lifetime); ``` **Other pipeline starters** — besides `rpl::on_next`, there are: - `rpl::on_error([=](Error &&e) { ... }, lifetime)` — handle errors - `rpl::on_done([=] { ... }, lifetime)` — handle stream completion - `rpl::on_next_error_done(nextCb, errorCb, doneCb, lifetime)` — handle all three The `Error` template parameter defaults to `rpl::no_error`: `rpl::producer`. **Key points:** - Explicitly `std::move` producers when starting pipelines - Pass `rpl::lifetime` to `on_...` methods or store returned lifetime - Use `rpl::duplicate(producer)` to reuse a producer multiple times - Combined producers automatically unpack tuples in lambdas (works with `rpl::map`, `rpl::filter`, and `rpl::on_next`) ================================================ FILE: CLAUDE.md ================================================ # Claude Code Pointer Read `AGENTS.md` and treat it as the canonical repository-wide instructions. ================================================ FILE: CMakeLists.txt ================================================ # This file is part of Telegram Desktop, # the official desktop application for the Telegram messaging service. # # For license and copyright information please follow this link: # https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL cmake_minimum_required(VERSION 3.25...3.31) set_property(GLOBAL PROPERTY USE_FOLDERS ON) # Apply qt6.11 patches to submodules at configure time. file(GLOB _submodule_patches "${CMAKE_SOURCE_DIR}/patches/*.patch") foreach(_patch ${_submodule_patches}) get_filename_component(_patch_name ${_patch} NAME) # Extract target submodule directory from patch filename (prefix before first '_'). string(REGEX MATCH "^([a-z]+)" _submodule ${_patch_name}) if (IS_DIRECTORY "${CMAKE_SOURCE_DIR}/${_submodule}") execute_process( COMMAND git apply --check ${_patch} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/${_submodule}" RESULT_VARIABLE _check_result OUTPUT_QUIET ERROR_QUIET ) if (_check_result EQUAL 0) execute_process( COMMAND git apply ${_patch} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/${_submodule}" ) message(STATUS "Applied patch: ${_patch_name}") endif() endif() endforeach() include(cmake/validate_special_target.cmake) include(cmake/version.cmake) desktop_app_parse_version(Telegram/build/version) if (NOT DEFINED CMAKE_CONFIGURATION_TYPES) set(configuration_types_init 1) endif() project(Telegram LANGUAGES C CXX VERSION ${desktop_app_version_cmake} DESCRIPTION "Official Telegram Desktop messenger" HOMEPAGE_URL "https://desktop.telegram.org" ) if (APPLE) enable_language(OBJC OBJCXX) endif() if (configuration_types_init AND CMAKE_CONFIGURATION_TYPES AND NOT MinSizeRel IN_LIST CMAKE_CONFIGURATION_TYPES) set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES};MinSizeRel" CACHE STRING "" FORCE) endif() set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Telegram) get_filename_component(third_party_loc "Telegram/ThirdParty" REALPATH) get_filename_component(submodules_loc "Telegram" REALPATH) get_filename_component(cmake_helpers_loc "cmake" REALPATH) if (NOT DESKTOP_APP_USE_PACKAGED AND WIN32) set(Python3_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/python/Scripts/python) endif() include(cmake/variables.cmake) include(cmake/nice_target_sources.cmake) include(cmake/target_compile_options_if_exists.cmake) include(cmake/target_link_frameworks.cmake) include(cmake/target_link_options_if_exists.cmake) include(cmake/init_target.cmake) include(cmake/generate_target.cmake) include(cmake/nuget.cmake) include(cmake/validate_d3d_compiler.cmake) include(cmake/target_prepare_qrc.cmake) include(cmake/options.cmake) include(cmake/external/qt/package.cmake) set(desktop_app_skip_libs glibmm variant ) add_subdirectory(cmake) add_subdirectory(Telegram) ================================================ FILE: LEGAL ================================================ This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. Copyright (c) 2014-2026 The Telegram Desktop Authors. Telegram Desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library. More information about the Telegram project: https://telegram.org Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE ================================================ FILE: LICENSE ================================================ Telegram Desktop is licensed under the GNU General Public License version 3 with the addition of the following special exception: In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: README.md ================================================ # Forkgram — Unofficial Telegram Messenger ![image](https://user-images.githubusercontent.com/4051126/43634235-402a8b74-9714-11e8-85c0-8ceb0844a3b0.png) Forkgram is the cutting-edge Telegram fork with small Quality-of-Life enhancements. [![Github All Releases](https://img.shields.io/github/downloads/Forkgram/tdesktop/total.svg?style=for-the-badge)](https://github.com/Forkgram/tdesktop/releases) [![Snap Store](https://img.shields.io/snapcraft/v/forkgram/latest/stable?style=for-the-badge)](https://snapcraft.io/forkgram) [![AUR](https://img.shields.io/aur/version/forkgram.svg?style=for-the-badge)](https://aur.archlinux.org/packages/forkgram) [![Chocolatey](https://img.shields.io/chocolatey/v/forkgram.svg?style=for-the-badge)](https://community.chocolatey.org/packages/forkgram) [![Scoop](https://img.shields.io/scoop/v/forkgram?bucket=extras&style=for-the-badge)](https://scoop.sh/#/apps?q=forkgram) [![Windows](https://img.shields.io/badge/Windows-x64%20%7C%20x86-blue?style=for-the-badge&logo=windows)](https://github.com/Forkgram/tdesktop/releases/latest) [![Homebrew Cask](https://img.shields.io/homebrew/cask/v/forkgram.svg?style=for-the-badge)](https://formulae.brew.sh/cask/forkgram) [![macOS](https://img.shields.io/badge/macOS-arm64%20%7C%20x86-black?style=for-the-badge&logo=apple)](https://github.com/Forkgram/tdesktop/releases/latest) ## Features: - Square avatars. *(Added XX.04.2017.)* Square tray icon. *(Updated 18.08.2018.)* - Opening any links with a custom URI Scheme. *(Added XX.04.2017 and updated 02.08.2019.)* - Checkmark "Delete for everyone" by default. *(Added XX.04.2017.)* ![image](https://user-images.githubusercontent.com/4051126/43633718-bee9dd4a-9712-11e8-8b24-57822bd20c04.png) - The fourth button in the title to "Always on top" window. (Windows only.) *(Added 16.05.2017.)* ![image](https://user-images.githubusercontent.com/4051126/43633763-d441eaa2-9712-11e8-8fb1-1e9e37af1d5e.png) - Showing the full timestamp if the user was online more than 1 hour ago. *(Added 14.06.2017.)* ![image](https://user-images.githubusercontent.com/4051126/27127613-5ead16c2-5104-11e7-8be0-f231b4bc3f6b.png) - Hotkeys for the mediaview was usability improved. [**Cheatsheet**](#cheatsheet). *(Added 29.06.2017.)* - Experimental auto-submitting of the local passcode. *(Added 29.06.2017.)* ![2018-08-10_01-50-45](https://user-images.githubusercontent.com/4051126/43930001-e5d1c1e8-9c3f-11e8-9ddd-ff1a60518d91.gif) - Showing date of forwarded messages in the title. *(Added 25.08.2017.)* ![image](https://user-images.githubusercontent.com/4051126/30046488-c94deb14-9213-11e7-8b2b-397ad6dbe6f7.png) - Button to go to the first message. *(Added 16.05.2018.)* ([Telegrate's](https://github.com/Sea-n/tdesktop) idea.) ![image](https://user-images.githubusercontent.com/4051126/40266489-7a31a1c8-5b54-11e8-868e-3c9877e0d6ff.png) - Option to remove fading of audio when it's paused/played. *(Added 10.08.2018.)* - Ability to see thumbs of the executable files as well as for other files. *(Added 14.08.2018.)* - Ability to search a selected text via the context menu. *(Added 22.01.2019.)* - Ability to show the last seen time of the user in list of the dialogs. *(Added 31.01.2019.)* - Option to enable a display of all recently used stickers. *(Added 09.02.2019.)* - Auto-replacing of "..." with "…". *(Added 17.02.2019.)* - Ability to bind Ctrl+6-9 dialogs with Ctrl+Shift+6-9 shortcuts. *(Added 11.06.2019.)* - Ability to send files to Saved Messages without the forward header. *(Added 23.06.2019.)* - Forward messages without quoting the original sender via `Share` box. *(Added 25.06.2019.)* ## Cheatsheet | Zoom in | Zoom out | Zoom reset | Old zoom in | Old zoom out | Old zoom reset | |----------------|-----------------|------------------|----------------|-----------------|------------------| | + | - | 0 | Ctrl`+`+ | Ctrl`+`- | Ctrl`+`0 | | Up arrow | Down arrow | * | Ctrl`+`] | Ctrl`+`_ | Middle button | | Scroll up | Scroll down | Middle button | Ctrl`+`= | Ctrl`+`Scroll down | | | ] | _ | | Ctrl`+`* | | | | = | | | Ctrl`+`Scroll up | | | You can scroll images by the wheel with pressed Ctrl. ## Downloads: You can download binaries from the Releases or from my [Telegram channel Forkgram](https://t.me/forkgram). ================================================ FILE: REVIEW.md ================================================ # Code Review Style Guide This file contains style and formatting rules that the review subagent must check and fix. These are mechanical issues that should always be caught during code review. ## Empty line before closing brace Always add an empty line before the closing brace of a **class** (which has one or more sections like `public:` / `private:`). Plain **structs** with just data members do NOT get a trailing empty line — they are compact: `struct Foo { data lines; };`. ```cpp // BAD: class MyClass { public: void foo(); private: int _value = 0; }; // GOOD: class MyClass { public: void foo(); private: int _value = 0; }; ``` ## Multi-line expressions — operators at the start of continuation lines When splitting an expression across multiple lines, place operators (like `&&`, `||`, `;`, `+`, etc.) at the **beginning** of continuation lines, not at the end of the previous line. This makes it immediately obvious from the left edge whether a line is a continuation or new code. ```cpp // BAD - continuation looks like scope code: if (const auto &lottie = animation->lottie; lottie && lottie->valid() && lottie->framesCount() > 1) { lottie->animate([=] { // GOOD - semicolon at start signals continuation: if (const auto &lottie = animation->lottie ; lottie && lottie->valid() && lottie->framesCount() > 1) { lottie->animate([=] { // BAD - trailing && makes next line look like independent code: if (veryLongExpression() && anotherLongExpression() && anotherOne()) { doSomething(); // GOOD - leading && clearly marks continuation: if (veryLongExpression() && anotherLongExpression() && anotherOne()) { doSomething(); ``` ## Minimize type checks — prefer direct cast over is + as Don't check a type and then cast — just cast and check for null. `asUser()` already returns `nullptr` when the peer is not a user, so calling `isUser()` first is redundant. The same applies to `asChannel()`, `asChat()`, etc. ```cpp // BAD - redundant isUser() check, then asUser(): if (peer && peer->isUser()) { peer->asUser()->setNoForwardFlags( // GOOD - just cast and null-check: if (const auto user = peer->asUser()) { user->setNoForwardFlags( ``` When you need a specific subtype, look up the specific subtype directly instead of loading a generic type and then casting: ```cpp // BAD - loads generic peer, then casts: if (const auto peer = session().data().peerLoaded(peerId) ; peer && peer->isUser()) { peer->asUser()->setNoForwardFlags( // GOOD - look up the specific subtype directly: const auto userId = peerToUser(peerId); if (const auto user = session().data().userLoaded(userId)) { user->setNoForwardFlags( ``` Avoid C++17 `if` with initializer (`;` inside the condition) when the code can be written more clearly with simple nested `if` statements or by extracting the value beforehand: ```cpp // BAD - complex if-with-initializer: if (const auto peer = session().data().peerLoaded(peerId) ; peer && peer->isUser()) { // GOOD - simple nested ifs when direct lookup isn't available: if (const auto peer = session().data().peerLoaded(peerId)) { if (const auto user = peer->asUser()) { ## Always initialize variables of basic types Never leave variables of basic types (`int`, `float`, `bool`, pointers, etc.) uninitialized. Custom types with constructors are fine — they initialize themselves. But for any basic type, always provide a default value (`= 0`, `= false`, `= nullptr`, etc.). This applies especially to class fields, where uninitialized members are a persistent source of bugs. The only exception is performance-critical hot paths where you can prove no read-from-uninitialized-memory occurs. For class fields there is no such exception — always initialize. ```cpp // BAD: int _bulletLeft; int _bulletTop; bool _expanded; SomeType *_pointer; // GOOD: int _bulletLeft = 0; int _bulletTop = 0; bool _expanded = false; SomeType *_pointer = nullptr; ``` ## Use tr:: projections for TextWithEntities Inside `tr::lng_...()` calls, always use the `tr::` projection helpers instead of their `Ui::Text::` equivalents. The `tr::` helpers are shorter and work uniformly as both placeholder wrappers and final projectors. | Instead of | Use | |---|---| | `Ui::Text::Bold(x)` | `tr::bold(x)` | | `Ui::Text::Italic(x)` | `tr::italic(x)` | | `Ui::Text::RichLangValue` | `tr::rich` | | `Ui::Text::WithEntities` | `tr::marked` | ```cpp // BAD - verbose Ui::Text:: functions: tr::lng_some_key( tr::now, lt_name, Ui::Text::Bold(name), lt_group, Ui::Text::Bold(group), Ui::Text::RichLangValue) // GOOD - concise tr:: helpers: tr::lng_some_key( tr::now, lt_name, tr::bold(name), lt_group, tr::bold(group), tr::rich) ``` Also use `tr::marked()` as the standard way to create `TextWithEntities` — not just as a projector: ```cpp // BAD - verbose constructor: auto text = TextWithEntities(); auto text = TextWithEntities{ u"hello"_q }; auto text = TextWithEntities().append(u"hello"_q); // GOOD - concise: auto text = tr::marked(); auto text = tr::marked(u"hello"_q); ``` ## Multi-line calls — one argument per line When a function call doesn't fit on one line, put each argument on its own line. Don't group "logical pairs" on the same line — it creates inconsistent line lengths and makes diffs noisier. ```cpp // BAD - pairs of arguments sharing lines: tr::lng_some_key( tr::now, lt_name, tr::bold(name), lt_group, tr::bold(group), tr::rich) // GOOD - one argument per line: tr::lng_some_key( tr::now, lt_name, tr::bold(name), lt_group, tr::bold(group), tr::rich) // Single-line is fine when everything fits: auto text = tr::lng_settings_title(tr::now); ``` ## std::optional access — avoid value() Do not call `std::optional::value()` because it throws an exception that is not available on older macOS targets. Use `has_value()`, `value_or()`, `operator bool()`, or `operator*` instead. ## Sort includes alphabetically, nested folders first After the file's own header, sort `#include` directives alphabetically with two special rules: 1. **Nested folders before files** in the same directory — like Finder / File Explorer (folders first, then files). E.g. `ui/controls/button.h` sorts before `ui/abstract_button.h`. 2. **Style includes (`styles/style_*.h`) always go last**, separated from the rest. ```cpp // BAD - arbitrary order, style mixed in: #include "media/audio/media_audio.h" #include "styles/style_media_player.h" #include "data/data_document.h" #include "apiwrap.h" // GOOD - alphabetical, folders first, styles last: #include "apiwrap.h" #include "data/data_document.h" #include "media/audio/media_audio.h" #include "styles/style_media_player.h" ``` ## Use C++17 nested namespace syntax Use `namespace A::B {` instead of nesting `namespace A { namespace B {`. The closing comment mirrors the opening: `} // namespace A::B`. ```cpp // BAD - old-style nesting: namespace Media { namespace Player { ... } // namespace Player } // namespace Media // GOOD - C++17 nested: namespace Media::Player { ... } // namespace Media::Player ``` ## Merge consecutive branches with identical bodies When two or more consecutive `if` / `else if` branches execute the same code, combine their conditions into a single branch. ```cpp // BAD - duplicated body: if (!document) { finalize(); return; } if (!document->isSong()) { finalize(); return; } // GOOD - combined: if (!document || !document->isSong()) { finalize(); return; } ``` ## Use base::take for read-and-reset When you need to read a variable's current value and reset it in one step, use `base::take(var)` instead of manually copying and clearing. `base::take` returns the old value and resets the variable to its default-constructed state. ```cpp // BAD - manual read + reset: if (_playing) { _listenedMs += crl::now() - _playStartedAt; _playing = false; } // GOOD: if (base::take(_playing)) { _listenedMs += crl::now() - _playStartedAt; } // BAD - copy fields then clear them one by one: const auto document = _document; const auto contextId = _contextId; _document = nullptr; _listenedMs = 0; if (!document) { return; } // GOOD - take everything upfront, then validate: const auto document = base::take(_document); const auto contextId = base::take(_contextId); const auto duration = static_cast(base::take(_listenedMs) / 1000); if (!document || duration <= 0) { return; } ``` ## Don't wrap tr:: lang keys in rpl::single `tr::lng_*()` (without `tr::now`) already returns an `rpl::producer`. Wrapping a snapshot in `rpl::single()` defeats live language switching — the value is captured once and never updates. Just call the lang key without `tr::now`. ```cpp // BAD - frozen snapshot, won't update on language change: rpl::single(tr::lng_ai_compose_title(tr::now)) // GOOD - live producer that updates automatically: tr::lng_ai_compose_title() ``` ## Extract method definitions from local classes When defining local classes (e.g. in anonymous namespaces), keep the class body compact — only declarations. Put all method definitions **after** all class definitions. This avoids unnecessary nesting inside the class body and keeps methods at the same indentation level as free functions. ```cpp // BAD - methods defined inline, adding a nesting level: class MyWidget final : public Ui::RpWidget { public: MyWidget(QWidget *parent) : RpWidget(parent) { // ... 20 lines of setup } void setActive(bool active) { _active = active; update(); } protected: void paintEvent(QPaintEvent *e) override { // ... 30 lines of painting } private: bool _active = false; }; // GOOD - class is a compact declaration, methods defined after: class MyWidget final : public Ui::RpWidget { public: MyWidget(QWidget *parent, QString label); void setActive(bool active); protected: void paintEvent(QPaintEvent *e) override; private: bool _active = false; }; MyWidget::MyWidget(QWidget *parent, QString label) : RpWidget(parent) { // ... 20 lines of setup } void MyWidget::setActive(bool active) { _active = active; update(); } void MyWidget::paintEvent(QPaintEvent *e) { // ... 30 lines of painting } ``` When there are multiple local classes, put **all class definitions first**, then **all method definitions** after. This keeps the declarations readable as an overview. ## Use RAII for resource cleanup When working with raw resources (Win32 HANDLEs, file descriptors, COM objects), use `gsl::finally` or a dedicated RAII wrapper for cleanup instead of calling release functions manually. Manual cleanup breaks when early returns are added later. ```cpp // BAD - manual cleanup, fragile with early returns: const auto snapshot = CreateToolhelp32Snapshot(...); if (snapshot != INVALID_HANDLE_VALUE) { // ... logic that might grow early returns ... CloseHandle(snapshot); } // GOOD - RAII guard, cleanup runs on any exit path: const auto snapshot = CreateToolhelp32Snapshot(...); if (snapshot == INVALID_HANDLE_VALUE) { return; } const auto guard = gsl::finally([&] { CloseHandle(snapshot); }); // ... logic, early returns are safe ... ``` ## Extract substantial logic from lambdas When a lambda grows beyond a few lines of self-contained logic, extract it into a named function (free function in anonymous namespace, or a private method). Lambdas should primarily be glue — captures, dispatch, short transforms. This applies when the lambda's captures are minimal and can easily become function parameters. When a lambda captures many variables from its surrounding context, it may be cleaner to keep it inline. ```cpp // BAD - substantial logic buried in a lambda: crl::async([=] { auto found = false; auto pe = PROCESSENTRY32(); pe.dwSize = sizeof(PROCESSENTRY32); const auto snapshot = CreateToolhelp32Snapshot(...); if (snapshot != INVALID_HANDLE_VALUE) { for (...) { if (/* match */) { found = true; break; } } CloseHandle(snapshot); } crl::on_main(weak, [=] { handle(found); }); }); // GOOD - logic extracted, lambda is just glue: crl::async([=] { const auto found = FindRunningReader(); crl::on_main(weak, [=] { handle(found); }); }); ``` ## Data-driven matching over chained conditions When comparing a value against multiple known constants, store them in a collection and loop instead of chaining `||` conditions. Easier to extend, less repetition, and reads as data rather than logic. ```cpp // BAD - repetitive chain, hard to extend: if (_wcsicmp(name, L"Narrator.exe") == 0 || _wcsicmp(name, L"nvda.exe") == 0 || _wcsicmp(name, L"jfw.exe") == 0 || _wcsicmp(name, L"Zt.exe") == 0) { // GOOD - data-driven, easy to extend: const auto list = std::array{ L"Narrator.exe", L"nvda.exe", L"jfw.exe", L"Zt.exe", }; for (const auto &entry : list) { if (_wcsicmp(name, entry) == 0) { return true; } } ``` ## Use !isHidden() for logic checks, not isVisible() When you call `show()` / `hide()` / `setVisible()` on a widget and later branch on that state, always check `!isHidden()` (the widget's own flag) — never `isVisible()`. `isVisible()` returns `true` only when the widget **and every ancestor** are visible, so it silently returns `false` during parent show-animations, before the parent is laid out, etc. `isHidden()` reflects exactly the flag you set. ```cpp // BAD — breaks when parent is still animating / not yet shown: child->setVisible(true); // ... later, in resizeGetHeight or similar: if (child->isVisible()) { // false if parent isn't visible yet! child->moveToRight(x, y, w); } // GOOD — checks the widget's own state: if (!child->isHidden()) { child->moveToRight(x, y, w); } ``` The same applies to any logic that depends on a previous `show()`/`hide()` call: skip blocks, layout branches, opacity decisions, etc. ## Consolidate make_state calls into a single State struct Every `make_state` is a separate heap allocation. When a function needs multiple pieces of lambda-captured mutable state, define a local `struct State` with all fields and call `make_state()` once, then capture the resulting pointer everywhere. ```cpp // BAD - two allocations: const auto shown = lifetime.make_state(false); const auto count = lifetime.make_state(0); // GOOD - one allocation: struct State { bool shown = false; int count = 0; }; const auto state = lifetime.make_state(); ``` ## Use trailing return type when the return type doesn't fit on one line When a function's return type is long enough that the declaration would need a line break between the return type and the function name, use trailing return type syntax (`auto ... -> Type`) to keep the function name on the opening line. ```cpp // BAD - return type orphaned on its own line: not_null SetupCaptionAiButton(SetupCaptionAiButtonArgs &&args); // GOOD - trailing return type keeps name visible: auto SetupCaptionAiButton(SetupCaptionAiButtonArgs &&args) -> not_null; ``` ## Mind data structure sizes and alignment When adding fields to a class or struct, consider the memory layout. A standalone `bool` between two pointer-sized fields wastes 7 bytes to alignment padding. Review new fields for packing opportunities: - If the struct already has bitfields, pack new boolean flags as `: 1` members rather than standalone `bool`. - If alignment leaves a gap (e.g., an `int` followed by a pointer), consider whether a new small field can fill it. - For classes instantiated in large quantities (per-message, per-element, per-row), every wasted byte is multiplied thousands of times. ```cpp // BAD - standalone bool adds 8 bytes (1 + 7 padding) before the next pointer: mutable bool _myFlag = false; mutable std::unique_ptr _foo; // GOOD - packed into existing bitfield group, no extra bytes: mutable uint32 _myFlag : 1 = 0; ``` ## Static member functions use PascalCase Non-static member functions use camelCase (`startBatch`, `finalize`). Static member functions use PascalCase (`ShouldTrack`, `Parse`, `Create`), matching the convention for free functions. ```cpp // BAD - camelCase for static method: [[nodiscard]] static bool shouldTrack(not_null item); // GOOD - PascalCase for static method: [[nodiscard]] static bool ShouldTrack(not_null item); ``` ================================================ FILE: Telegram/CMakeLists.txt ================================================ # This file is part of Telegram Desktop, # the official desktop application for the Telegram messaging service. # # For license and copyright information please follow this link: # https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL add_executable(Telegram WIN32 MACOSX_BUNDLE) init_non_host_target(Telegram) add_subdirectory(lib_rpl) add_subdirectory(lib_crl) add_subdirectory(lib_base) add_subdirectory(lib_ui) add_subdirectory(lib_tl) add_subdirectory(lib_spellcheck) add_subdirectory(lib_storage) add_subdirectory(lib_lottie) add_subdirectory(lib_qr) add_subdirectory(lib_translate) add_subdirectory(lib_webrtc) add_subdirectory(lib_webview) add_subdirectory(codegen) get_filename_component(src_loc SourceFiles REALPATH) get_filename_component(res_loc Resources REALPATH) include(cmake/telegram_options.cmake) include(cmake/lib_ffmpeg.cmake) include(cmake/lib_stripe.cmake) include(cmake/lib_tgcalls.cmake) include(cmake/lib_prisma.cmake) include(cmake/td_export.cmake) include(cmake/td_iv.cmake) include(cmake/td_lang.cmake) include(cmake/td_mtproto.cmake) include(cmake/td_scheme.cmake) include(cmake/td_tde2e.cmake) include(cmake/td_ui.cmake) include(cmake/telegram_apple_swift_runtime.cmake) include(cmake/generate_appstream_changelog.cmake) include(cmake/td_forkgram.cmake) if (DESKTOP_APP_TEST_APPS) include(cmake/tests.cmake) endif() if (WIN32) include(cmake/generate_midl.cmake) generate_midl(Telegram ${src_loc} platform/win/windows_quiethours.idl platform/win/windows_toastactivator.idl ) endif() set_target_properties(Telegram PROPERTIES AUTOMOC ON) target_link_libraries(Telegram PRIVATE tdesktop::lib_tgcalls # Order in this list defines the order of include paths in command line. # We need to place desktop-app::external_minizip this early to have its # include paths (usually ${PREFIX}/include/minizip) before any depend that # would add ${PREFIX}/include. This path may have a different , # for example installed by libzip (https://libzip.org). desktop-app::external_minizip tdesktop::td_export tdesktop::td_iv tdesktop::td_lang tdesktop::td_mtproto tdesktop::td_scheme tdesktop::td_tde2e tdesktop::td_ui tdesktop::td_forkgram desktop-app::lib_webrtc desktop-app::lib_base desktop-app::lib_crl desktop-app::lib_ui desktop-app::lib_tl desktop-app::lib_spellcheck desktop-app::lib_storage desktop-app::lib_lottie desktop-app::lib_qr desktop-app::lib_translate desktop-app::lib_webview desktop-app::lib_ffmpeg desktop-app::lib_stripe desktop-app::external_rlottie desktop-app::external_zlib desktop-app::external_kcoreaddons desktop-app::external_qt_static_plugins desktop-app::external_qt desktop-app::external_qr_code_generator desktop-app::external_zbar desktop-app::external_crash_reports desktop-app::external_auto_updates desktop-app::external_openssl desktop-app::external_openal desktop-app::external_xxhash ) if (NOT DESKTOP_APP_DISABLE_SWIFT6) telegram_add_apple_swift_runtime(Telegram) endif() target_precompile_headers(Telegram PRIVATE $<$:${src_loc}/stdafx.h>) nice_target_sources(Telegram ${src_loc} PRIVATE ${style_files} api/api_as_copy.cpp api/api_as_copy.h api/api_attached_stickers.cpp api/api_attached_stickers.h api/api_authorizations.cpp api/api_authorizations.h api/api_blocked_peers.cpp api/api_blocked_peers.h api/api_bot.cpp api/api_bot.h api/api_chat_filters.cpp api/api_chat_filters.h api/api_chat_filters_remove_manager.cpp api/api_chat_filters_remove_manager.h api/api_chat_invite.cpp api/api_chat_invite.h api/api_chat_links.cpp api/api_chat_links.h api/api_chat_participants.cpp api/api_chat_participants.h api/api_cloud_password.cpp api/api_cloud_password.h data/data_search_calendar.h data/data_search_calendar.cpp api/api_common.cpp api/api_common.h api/api_confirm_phone.cpp api/api_confirm_phone.h api/api_compose_with_ai.cpp api/api_compose_with_ai.h api/api_credits.cpp api/api_credits.h api/api_credits_history_entry.cpp api/api_credits_history_entry.h api/api_earn.cpp api/api_earn.h api/api_editing.cpp api/api_editing.h api/api_filter_updates.h api/api_global_privacy.cpp api/api_global_privacy.h api/api_hash.cpp api/api_hash.h api/api_invite_links.cpp api/api_invite_links.h api/api_media.cpp api/api_media.h api/api_messages_search.cpp api/api_messages_search.h api/api_messages_search_merged.cpp api/api_messages_search_merged.h api/api_peer_colors.cpp api/api_peer_colors.h api/api_peer_photo.cpp api/api_peer_photo.h api/api_peer_search.cpp api/api_peer_search.h api/api_polls.cpp api/api_polls.h api/api_premium.cpp api/api_premium.h api/api_premium_option.cpp api/api_premium_option.h api/api_reactions_notify_settings.cpp api/api_reactions_notify_settings.h api/api_read_metrics.cpp api/api_read_metrics.h api/api_report.cpp api/api_report.h api/api_ringtones.cpp api/api_ringtones.h api/api_self_destruct.cpp api/api_self_destruct.h api/api_send_progress.cpp api/api_send_progress.h api/api_sending.cpp api/api_sending.h api/api_sensitive_content.cpp api/api_sensitive_content.h api/api_single_message_search.cpp api/api_single_message_search.h api/api_statistics.cpp api/api_statistics.h api/api_statistics_data_deserialize.cpp api/api_statistics_data_deserialize.h api/api_statistics_sender.cpp api/api_statistics_sender.h api/api_suggest_post.cpp api/api_suggest_post.h api/api_text_entities.cpp api/api_text_entities.h api/api_todo_lists.cpp api/api_todo_lists.h api/api_toggling_media.cpp api/api_toggling_media.h api/api_transcribes.cpp api/api_transcribes.h api/api_unread_things.cpp api/api_unread_things.h api/api_updates.cpp api/api_updates.h api/api_user_names.cpp api/api_user_names.h api/api_user_privacy.cpp api/api_user_privacy.h api/api_views.cpp api/api_views.h api/api_websites.cpp api/api_websites.h api/api_who_reacted.cpp api/api_who_reacted.h boxes/filters/edit_filter_box.cpp boxes/filters/edit_filter_box.h boxes/filters/edit_filter_chats_list.cpp boxes/filters/edit_filter_chats_list.h boxes/filters/edit_filter_chats_preview.cpp boxes/filters/edit_filter_chats_preview.h boxes/filters/edit_filter_links.cpp boxes/filters/edit_filter_links.h boxes/peers/add_bot_to_chat_box.cpp boxes/peers/add_bot_to_chat_box.h boxes/peers/add_participants_box.cpp boxes/peers/add_participants_box.h boxes/peers/channel_ownership_transfer.cpp boxes/peers/channel_ownership_transfer.h boxes/peers/choose_peer_box.cpp boxes/peers/choose_peer_box.h boxes/peers/create_managed_bot_box.cpp boxes/peers/create_managed_bot_box.h boxes/peers/edit_contact_box.cpp boxes/peers/edit_contact_box.h boxes/peers/edit_forum_topic_box.cpp boxes/peers/edit_forum_topic_box.h boxes/peers/edit_discussion_link_box.cpp boxes/peers/edit_discussion_link_box.h boxes/peers/edit_members_visible.cpp boxes/peers/edit_members_visible.h boxes/peers/edit_participant_box.cpp boxes/peers/edit_participant_box.h boxes/peers/edit_tag_control.cpp boxes/peers/edit_tag_control.h boxes/peers/edit_participants_box.cpp boxes/peers/edit_participants_box.h boxes/peers/edit_peer_color_box.cpp boxes/peers/edit_peer_color_box.h boxes/peers/edit_peer_common.h boxes/peers/edit_peer_info_box.cpp boxes/peers/edit_peer_info_box.h boxes/peers/edit_peer_invite_link.cpp boxes/peers/edit_peer_invite_link.h boxes/peers/edit_peer_invite_links.cpp boxes/peers/edit_peer_invite_links.h boxes/peers/edit_peer_permissions_box.cpp boxes/peers/edit_peer_permissions_box.h boxes/peers/edit_peer_reactions.cpp boxes/peers/edit_peer_reactions.h boxes/peers/edit_peer_requests_box.cpp boxes/peers/edit_peer_requests_box.h boxes/peers/edit_peer_type_box.cpp boxes/peers/edit_peer_type_box.h boxes/peers/edit_peer_usernames_list.cpp boxes/peers/edit_peer_usernames_list.h boxes/peers/peer_short_info_box.cpp boxes/peers/peer_short_info_box.h boxes/peers/prepare_short_info_box.cpp boxes/peers/prepare_short_info_box.h boxes/peers/replace_boost_box.cpp boxes/peers/replace_boost_box.h boxes/peers/tag_info_box.cpp boxes/peers/tag_info_box.h boxes/peers/verify_peers_box.cpp boxes/peers/verify_peers_box.h boxes/about_box.cpp boxes/about_box.h boxes/about_sponsored_box.cpp boxes/about_sponsored_box.h boxes/abstract_box.cpp boxes/abstract_box.h boxes/add_contact_box.cpp boxes/add_contact_box.h boxes/auto_lock_box.cpp boxes/auto_lock_box.h boxes/auto_download_box.cpp boxes/auto_download_box.h boxes/background_box.cpp boxes/background_box.h boxes/background_preview_box.cpp boxes/background_preview_box.h boxes/choose_filter_box.cpp boxes/choose_filter_box.h boxes/connection_box.cpp boxes/connection_box.h boxes/create_poll_box.cpp boxes/create_poll_box.h boxes/delete_messages_box.cpp boxes/delete_messages_box.h boxes/dictionaries_manager.cpp boxes/dictionaries_manager.h boxes/download_path_box.cpp boxes/download_path_box.h boxes/edit_caption_box.cpp boxes/edit_caption_box.h boxes/edit_privacy_box.cpp boxes/edit_privacy_box.h boxes/edit_todo_list_box.cpp boxes/edit_todo_list_box.h boxes/gift_credits_box.cpp boxes/gift_credits_box.h boxes/gift_premium_box.cpp boxes/gift_premium_box.h boxes/language_box.cpp boxes/language_box.h boxes/local_storage_box.cpp boxes/local_storage_box.h boxes/max_invite_box.cpp boxes/max_invite_box.h boxes/moderate_messages_box.cpp boxes/moderate_messages_box.h boxes/peer_list_box.cpp boxes/peer_list_box.h boxes/peer_list_controllers.cpp boxes/peer_list_controllers.h boxes/peer_list_widgets.cpp boxes/peer_list_widgets.h boxes/peer_lists_box.cpp boxes/peer_lists_box.h boxes/passcode_box.cpp boxes/passcode_box.h boxes/phone_banned_box.cpp boxes/phone_banned_box.h boxes/pin_messages_box.cpp boxes/pin_messages_box.h boxes/premium_limits_box.cpp boxes/premium_limits_box.h boxes/premium_preview_box.cpp boxes/premium_preview_box.h boxes/reactions_settings_box.cpp boxes/reactions_settings_box.h boxes/report_messages_box.cpp boxes/report_messages_box.h boxes/ringtones_box.cpp boxes/ringtones_box.h boxes/select_future_owner_box.cpp boxes/select_future_owner_box.h boxes/self_destruction_box.cpp boxes/self_destruction_box.h boxes/send_credits_box.cpp boxes/send_credits_box.h boxes/send_gif_with_caption_box.cpp boxes/send_gif_with_caption_box.h boxes/send_files_box.cpp boxes/send_files_box.h boxes/share_box.cpp boxes/share_box.h boxes/star_gift_auction_box.cpp boxes/star_gift_auction_box.h boxes/star_gift_box.cpp boxes/star_gift_box.h boxes/star_gift_cover_box.cpp boxes/star_gift_cover_box.h boxes/star_gift_craft_animation.cpp boxes/star_gift_craft_animation.h boxes/star_gift_craft_box.cpp boxes/star_gift_craft_box.h boxes/star_gift_preview_box.cpp boxes/star_gift_preview_box.h boxes/star_gift_resale_box.cpp boxes/star_gift_resale_box.h boxes/sticker_set_box.cpp boxes/sticker_set_box.h boxes/stickers_box.cpp boxes/stickers_box.h boxes/transfer_gift_box.cpp boxes/transfer_gift_box.h boxes/compose_ai_box.cpp boxes/compose_ai_box.h boxes/translate_box.cpp boxes/translate_box.h boxes/url_auth_box.cpp boxes/url_auth_box.h boxes/username_box.cpp boxes/username_box.h calls/group/calls_choose_join_as.cpp calls/group/calls_choose_join_as.h calls/group/calls_cover_item.cpp calls/group/calls_cover_item.h calls/group/calls_group_call.cpp calls/group/calls_group_call.h calls/group/calls_group_common.cpp calls/group/calls_group_common.h calls/group/calls_group_invite_controller.cpp calls/group/calls_group_invite_controller.h calls/group/calls_group_members.cpp calls/group/calls_group_members.h calls/group/calls_group_members_row.cpp calls/group/calls_group_members_row.h calls/group/calls_group_menu.cpp calls/group/calls_group_menu.h calls/group/calls_group_message_encryption.cpp calls/group/calls_group_message_encryption.h calls/group/calls_group_message_field.cpp calls/group/calls_group_message_field.h calls/group/calls_group_messages.cpp calls/group/calls_group_messages.h calls/group/calls_group_messages_ui.cpp calls/group/calls_group_messages_ui.h calls/group/calls_group_panel.cpp calls/group/calls_group_panel.h calls/group/calls_group_rtmp.cpp calls/group/calls_group_rtmp.h calls/group/calls_group_settings.cpp calls/group/calls_group_settings.h calls/group/calls_group_stars_box.cpp calls/group/calls_group_stars_box.h calls/group/calls_group_toasts.cpp calls/group/calls_group_toasts.h calls/group/calls_group_viewport.cpp calls/group/calls_group_viewport.h calls/group/calls_group_viewport_opengl.cpp calls/group/calls_group_viewport_opengl.h calls/group/calls_group_viewport_raster.cpp calls/group/calls_group_viewport_raster.h calls/group/calls_group_viewport_rhi.cpp calls/group/calls_group_viewport_rhi.h calls/group/calls_group_viewport_tile.cpp calls/group/calls_group_viewport_tile.h calls/group/calls_volume_item.cpp calls/group/calls_volume_item.h calls/calls_box_controller.cpp calls/calls_box_controller.h calls/calls_call.cpp calls/calls_call.h calls/calls_emoji_fingerprint.cpp calls/calls_emoji_fingerprint.h calls/calls_instance.cpp calls/calls_instance.h calls/calls_panel.cpp calls/calls_panel.h calls/calls_panel_background.cpp calls/calls_panel_background.h calls/calls_signal_bars.cpp calls/calls_signal_bars.h calls/calls_top_bar.cpp calls/calls_top_bar.h calls/calls_userpic.cpp calls/calls_userpic.h calls/calls_video_bubble.cpp calls/calls_video_bubble.h calls/calls_video_incoming.cpp calls/calls_video_incoming.h calls/calls_window.cpp calls/calls_window.h chat_helpers/compose/compose_features.h chat_helpers/compose/compose_show.cpp chat_helpers/compose/compose_show.h chat_helpers/bot_command.cpp chat_helpers/bot_command.h chat_helpers/bot_keyboard.cpp chat_helpers/bot_keyboard.h chat_helpers/emoji_interactions.cpp chat_helpers/emoji_interactions.h chat_helpers/emoji_keywords.cpp chat_helpers/emoji_keywords.h chat_helpers/emoji_list_widget.cpp chat_helpers/emoji_list_widget.h chat_helpers/emoji_sets_manager.cpp chat_helpers/emoji_sets_manager.h chat_helpers/emoji_suggestions_widget.cpp chat_helpers/emoji_suggestions_widget.h chat_helpers/field_autocomplete.cpp chat_helpers/field_autocomplete.h chat_helpers/gifs_list_widget.cpp chat_helpers/gifs_list_widget.h chat_helpers/message_field.cpp chat_helpers/message_field.h chat_helpers/share_message_phrase_factory.cpp chat_helpers/share_message_phrase_factory.h chat_helpers/spellchecker_common.cpp chat_helpers/spellchecker_common.h chat_helpers/stickers_dice_pack.cpp chat_helpers/stickers_dice_pack.h chat_helpers/stickers_emoji_pack.cpp chat_helpers/stickers_emoji_pack.h chat_helpers/stickers_gift_box_pack.cpp chat_helpers/stickers_gift_box_pack.h chat_helpers/stickers_list_footer.cpp chat_helpers/stickers_list_footer.h chat_helpers/stickers_list_widget.cpp chat_helpers/stickers_list_widget.h chat_helpers/stickers_lottie.cpp chat_helpers/stickers_lottie.h chat_helpers/tabbed_panel.cpp chat_helpers/tabbed_panel.h chat_helpers/tabbed_section.cpp chat_helpers/tabbed_section.h chat_helpers/tabbed_selector.cpp chat_helpers/tabbed_selector.h chat_helpers/ttl_media_layer_widget.cpp chat_helpers/ttl_media_layer_widget.h core/application.cpp core/application.h core/cached_webview_availability.h core/bank_card_click_handler.cpp core/bank_card_click_handler.h core/base_integration.cpp core/base_integration.h core/changelogs.cpp core/changelogs.h core/click_handler_types.cpp core/click_handler_types.h core/core_cloud_password.cpp core/core_cloud_password.h core/core_settings.cpp core/core_settings.h core/fork_settings.cpp core/fork_settings.h core/core_settings_proxy.cpp core/core_settings_proxy.h core/crash_report_window.cpp core/crash_report_window.h core/crash_reports.cpp core/crash_reports.h core/credits_amount.h core/deadlock_detector.h core/deep_links/deep_links_chats.cpp core/deep_links/deep_links_chats.h core/deep_links/deep_links_contacts.cpp core/deep_links/deep_links_contacts.h core/deep_links/deep_links_new.cpp core/deep_links/deep_links_new.h core/deep_links/deep_links_router.cpp core/deep_links/deep_links_router.h core/deep_links/deep_links_settings.cpp core/deep_links/deep_links_settings.h core/deep_links/deep_links_types.h core/file_utilities.cpp core/file_utilities.h core/launcher.cpp core/launcher.h core/local_url_handlers.cpp core/local_url_handlers.h core/phone_click_handler.cpp core/phone_click_handler.h core/sandbox.cpp core/sandbox.h core/shortcuts.cpp core/shortcuts.h core/ui_integration.cpp core/ui_integration.h core/update_checker.cpp core/update_checker.h core/utils.cpp core/utils.h core/version.h countries/countries_manager.cpp countries/countries_manager.h data/business/data_business_chatbots.cpp data/business/data_business_chatbots.h data/business/data_business_common.cpp data/business/data_business_common.h data/business/data_business_info.cpp data/business/data_business_info.h data/business/data_shortcut_messages.cpp data/business/data_shortcut_messages.h data/components/credits.cpp data/components/credits.h data/components/factchecks.cpp data/components/factchecks.h data/components/gift_auctions.cpp data/components/gift_auctions.h data/components/location_pickers.cpp data/components/location_pickers.h data/components/passkeys.cpp data/components/passkeys.h data/components/promo_suggestions.cpp data/components/promo_suggestions.h data/components/recent_peers.cpp data/components/recent_peers.h data/components/recent_shared_media_gifts.cpp data/components/recent_shared_media_gifts.h data/components/scheduled_messages.cpp data/components/scheduled_messages.h data/components/sponsored_messages.cpp data/components/sponsored_messages.h data/components/top_peers.cpp data/components/top_peers.h data/notify/data_notify_settings.cpp data/notify/data_notify_settings.h data/notify/data_peer_notify_settings.cpp data/notify/data_peer_notify_settings.h data/notify/data_peer_notify_volume.cpp data/notify/data_peer_notify_volume.h data/stickers/data_custom_emoji.cpp data/stickers/data_custom_emoji.h data/stickers/data_stickers_set.cpp data/stickers/data_stickers_set.h data/stickers/data_stickers.cpp data/stickers/data_stickers.h data/data_abstract_sparse_ids.h data/data_abstract_structure.cpp data/data_abstract_structure.h data/data_audio_msg_id.cpp data/data_audio_msg_id.h data/data_auto_download.cpp data/data_auto_download.h data/data_boosts.h data/data_bot_app.cpp data/data_bot_app.h data/data_chat.cpp data/data_chat.h data/data_chat_filters.cpp data/data_chat_filters.h data/data_chat_participant_status.cpp data/data_chat_participant_status.h data/data_changes.cpp data/data_changes.h data/data_channel.cpp data/data_channel.h data/data_channel_admins.cpp data/data_channel_admins.h data/data_cloud_file.cpp data/data_cloud_file.h data/data_cloud_themes.cpp data/data_cloud_themes.h data/data_document.cpp data/data_document.h data/data_document_media.cpp data/data_document_media.h data/data_document_resolver.cpp data/data_document_resolver.h data/data_download_manager.cpp data/data_download_manager.h data/data_drafts.cpp data/data_drafts.h data/data_emoji_statuses.cpp data/data_emoji_statuses.h data/data_folder.cpp data/data_folder.h data/data_forum.cpp data/data_forum.h data/data_forum_icons.cpp data/data_forum_icons.h data/data_forum_topic.cpp data/data_forum_topic.h data/data_file_click_handler.cpp data/data_file_click_handler.h data/data_file_origin.cpp data/data_file_origin.h data/data_flags.h data/data_game.cpp data/data_game.h data/data_group_call.cpp data/data_group_call.h data/data_groups.cpp data/data_groups.h data/data_histories.cpp data/data_histories.h data/data_history_messages.cpp data/data_history_messages.h data/data_lastseen_status.h data/data_location.cpp data/data_location.h data/data_media_preload.cpp data/data_media_preload.h data/data_media_rotation.cpp data/data_media_rotation.h data/data_media_types.cpp data/data_media_types.h # data/data_messages.cpp # data/data_messages.h data/data_message_reaction_id.cpp data/data_message_reaction_id.h data/data_message_reactions.cpp data/data_message_reactions.h data/data_msg_id.h data/data_peer.cpp data/data_peer.h data/data_peer_bot_command.cpp data/data_peer_bot_command.h data/data_peer_bot_commands.cpp data/data_peer_bot_commands.h data/data_peer_common.h data/data_peer_id.cpp data/data_peer_id.h data/data_peer_values.cpp data/data_peer_values.h data/data_photo.cpp data/data_photo.h data/data_photo_media.cpp data/data_photo_media.h data/data_poll.cpp data/data_poll.h data/data_poll_messages.cpp data/data_poll_messages.h data/data_premium_limits.cpp data/data_premium_limits.h data/data_pts_waiter.cpp data/data_pts_waiter.h data/data_replies_list.cpp data/data_replies_list.h data/data_reply_preview.cpp data/data_reply_preview.h data/data_report.h data/data_saved_messages.cpp data/data_saved_messages.h data/data_saved_music.cpp data/data_saved_music.h data/data_saved_sublist.cpp data/data_saved_sublist.h data/data_search_controller.cpp data/data_search_controller.h data/data_send_action.cpp data/data_send_action.h data/data_session.cpp data/data_session.h data/data_shared_media.cpp data/data_shared_media.h data/data_sparse_ids.cpp data/data_sparse_ids.h data/data_star_gift.cpp data/data_star_gift.h data/data_statistics.h data/data_stories.cpp data/data_stories.h data/data_stories_ids.cpp data/data_stories_ids.h data/data_story.cpp data/data_story.h data/data_streaming.cpp data/data_streaming.h data/data_thread.cpp data/data_thread.h data/data_todo_list.cpp data/data_todo_list.h data/data_types.cpp data/data_types.h data/data_unread_value.cpp data/data_unread_value.h data/data_user.cpp data/data_user.h data/data_user_photos.cpp data/data_user_photos.h data/data_user_names.cpp data/data_user_names.h data/data_wall_paper.cpp data/data_wall_paper.h data/data_web_page.cpp data/data_web_page.h dialogs/ui/dialogs_layout.cpp dialogs/ui/dialogs_layout.h dialogs/ui/dialogs_message_view.cpp dialogs/ui/dialogs_message_view.h dialogs/ui/dialogs_stories_content.cpp dialogs/ui/dialogs_stories_content.h dialogs/ui/dialogs_suggestions.cpp dialogs/ui/dialogs_suggestions.h dialogs/ui/dialogs_topics_view.cpp dialogs/ui/dialogs_topics_view.h dialogs/ui/dialogs_video_userpic.cpp dialogs/ui/dialogs_video_userpic.h dialogs/dialogs_entry.cpp dialogs/dialogs_entry.h dialogs/dialogs_indexed_list.cpp dialogs/dialogs_indexed_list.h dialogs/dialogs_inner_widget.cpp dialogs/dialogs_inner_widget.h dialogs/dialogs_key.cpp dialogs/dialogs_key.h dialogs/dialogs_list.cpp dialogs/dialogs_list.h dialogs/dialogs_main_list.cpp dialogs/dialogs_main_list.h dialogs/dialogs_pinned_list.cpp dialogs/dialogs_pinned_list.h dialogs/dialogs_quick_action.cpp dialogs/dialogs_quick_action.h dialogs/dialogs_row.cpp dialogs/dialogs_row.h dialogs/dialogs_search_from_controllers.cpp dialogs/dialogs_search_from_controllers.h dialogs/dialogs_search_tags.cpp dialogs/dialogs_search_tags.h dialogs/dialogs_search_posts.cpp dialogs/dialogs_search_posts.h dialogs/dialogs_top_bar_suggestion.cpp dialogs/dialogs_top_bar_suggestion.h dialogs/dialogs_widget.cpp dialogs/dialogs_widget.h editor/color_picker.cpp editor/color_picker.h editor/controllers/controllers.h editor/controllers/stickers_panel_controller.cpp editor/controllers/stickers_panel_controller.h editor/editor_paint.cpp editor/editor_paint.h editor/photo_editor.cpp editor/photo_editor.h editor/photo_editor_content.cpp editor/photo_editor_content.h editor/photo_editor_controls.cpp editor/photo_editor_controls.h editor/photo_editor_layer_widget.cpp editor/photo_editor_layer_widget.h editor/scene/scene_item_sticker.cpp editor/scene/scene_item_sticker.h export/export_manager.cpp export/export_manager.h export/view/export_view_content.cpp export/view/export_view_content.h export/view/export_view_panel_controller.cpp export/view/export_view_panel_controller.h export/view/export_view_progress.cpp export/view/export_view_progress.h export/view/export_view_settings.cpp export/view/export_view_settings.h export/view/export_view_top_bar.cpp export/view/export_view_top_bar.h forkgram/gpu_demo_renderer.cpp forkgram/gpu_demo_renderer.h forkgram/uri_menu.cpp forkgram/uri_menu.h history/admin_log/history_admin_log_filter.cpp history/admin_log/history_admin_log_filter.h history/admin_log/history_admin_log_inner.cpp history/admin_log/history_admin_log_inner.h history/admin_log/history_admin_log_item.cpp history/admin_log/history_admin_log_item.h history/admin_log/history_admin_log_section.cpp history/admin_log/history_admin_log_section.h history/view/controls/compose_controls_common.h history/view/controls/history_view_compose_ai_button.cpp history/view/controls/history_view_compose_ai_button.h history/view/controls/history_view_compose_ai_tooltip.cpp history/view/controls/history_view_compose_ai_tooltip.h history/view/controls/history_view_compose_controls.cpp history/view/controls/history_view_compose_controls.h history/view/controls/history_view_compose_media_edit_manager.cpp history/view/controls/history_view_compose_media_edit_manager.h history/view/controls/history_view_compose_search.cpp history/view/controls/history_view_compose_search.h history/view/controls/history_view_draft_options.cpp history/view/controls/history_view_draft_options.h history/view/controls/history_view_forward_panel.cpp history/view/controls/history_view_forward_panel.h history/view/controls/history_view_suggest_options.cpp history/view/controls/history_view_suggest_options.h history/view/controls/history_view_ttl_button.cpp history/view/controls/history_view_ttl_button.h history/view/controls/history_view_voice_record_bar.cpp history/view/controls/history_view_voice_record_bar.h history/view/controls/history_view_webpage_processor.cpp history/view/controls/history_view_webpage_processor.h history/view/media/history_view_birthday_suggestion.cpp history/view/media/history_view_birthday_suggestion.h history/view/media/history_view_call.cpp history/view/media/history_view_call.h history/view/media/history_view_contact.cpp history/view/media/history_view_contact.h history/view/media/history_view_custom_emoji.cpp history/view/media/history_view_custom_emoji.h history/view/media/history_view_dice.cpp history/view/media/history_view_dice.h history/view/media/history_view_document.cpp history/view/media/history_view_document.h history/view/media/history_view_file.cpp history/view/media/history_view_file.h history/view/media/history_view_game.cpp history/view/media/history_view_game.h history/view/media/history_view_gif.cpp history/view/media/history_view_gif.h history/view/media/history_view_giveaway.cpp history/view/media/history_view_giveaway.h history/view/media/history_view_invoice.cpp history/view/media/history_view_invoice.h history/view/media/history_view_large_emoji.cpp history/view/media/history_view_large_emoji.h history/view/media/history_view_location.cpp history/view/media/history_view_location.h history/view/media/history_view_media.cpp history/view/media/history_view_media.h history/view/media/history_view_media_common.cpp history/view/media/history_view_media_common.h history/view/media/history_view_media_generic.cpp history/view/media/history_view_media_generic.h history/view/media/history_view_media_grouped.cpp history/view/media/history_view_media_grouped.h history/view/media/history_view_media_spoiler.cpp history/view/media/history_view_media_spoiler.h history/view/media/history_view_media_unwrapped.cpp history/view/media/history_view_media_unwrapped.h history/view/media/history_view_no_forwards_request.cpp history/view/media/history_view_no_forwards_request.h history/view/media/history_view_photo.cpp history/view/media/history_view_photo.h history/view/media/history_view_poll.cpp history/view/media/history_view_poll.h history/view/media/menu/history_view_poll_menu.cpp history/view/media/menu/history_view_poll_menu.h history/view/media/history_view_premium_gift.cpp history/view/media/history_view_premium_gift.h history/view/media/history_view_save_document_action.cpp history/view/media/history_view_save_document_action.h history/view/media/history_view_service_box.cpp history/view/media/history_view_service_box.h history/view/media/history_view_similar_channels.cpp history/view/media/history_view_similar_channels.h history/view/media/history_view_slot_machine.cpp history/view/media/history_view_slot_machine.h history/view/media/history_view_sticker.cpp history/view/media/history_view_sticker.h history/view/media/history_view_sticker_player.cpp history/view/media/history_view_sticker_player.h history/view/media/history_view_sticker_player_abstract.h history/view/media/history_view_story_mention.cpp history/view/media/history_view_story_mention.h history/view/media/history_view_suggest_decision.cpp history/view/media/history_view_suggest_decision.h history/view/media/history_view_theme_document.cpp history/view/media/history_view_theme_document.h history/view/media/history_view_todo_list.cpp history/view/media/history_view_todo_list.h history/view/media/history_view_unique_gift.cpp history/view/media/history_view_unique_gift.h history/view/media/history_view_userpic_suggestion.cpp history/view/media/history_view_userpic_suggestion.h history/view/media/history_view_web_page.cpp history/view/media/history_view_web_page.h history/view/reactions/history_view_reactions.cpp history/view/reactions/history_view_reactions.h history/view/reactions/history_view_reactions_button.cpp history/view/reactions/history_view_reactions_button.h history/view/reactions/history_view_reactions_list.cpp history/view/reactions/history_view_reactions_list.h history/view/reactions/history_view_reactions_selector.cpp history/view/reactions/history_view_reactions_selector.h history/view/reactions/history_view_reactions_strip.cpp history/view/reactions/history_view_reactions_strip.h history/view/reactions/history_view_reactions_tabs.cpp history/view/reactions/history_view_reactions_tabs.h history/view/history_view_top_peers_selector.cpp history/view/history_view_top_peers_selector.h history/view/history_view_about_view.cpp history/view/history_view_about_view.h history/view/history_view_bottom_info.cpp history/view/history_view_bottom_info.h history/view/history_view_chat_preview.cpp history/view/history_view_chat_preview.h history/view/history_view_chat_section.cpp history/view/history_view_chat_section.h history/view/history_view_contact_status.cpp history/view/history_view_contact_status.h history/view/history_view_context_menu.cpp history/view/history_view_context_menu.h history/view/history_view_context_menu_fork.cpp history/view/history_view_context_menu_fork.h history/view/history_view_corner_buttons.cpp history/view/history_view_corner_buttons.h history/view/history_view_cursor_state.cpp history/view/history_view_cursor_state.h history/view/history_view_draw_to_reply.cpp history/view/history_view_draw_to_reply.h history/view/history_view_add_poll_option.cpp history/view/history_view_add_poll_option.h history/view/history_view_element_overlay.cpp history/view/history_view_element_overlay.h history/view/history_view_element.cpp history/view/history_view_element.h history/view/history_view_emoji_interactions.cpp history/view/history_view_emoji_interactions.h history/view/history_view_empty_list_bubble.cpp history/view/history_view_empty_list_bubble.h history/view/history_view_fake_items.cpp history/view/history_view_fake_items.h history/view/history_view_group_call_bar.cpp history/view/history_view_group_call_bar.h history/view/history_view_group_members_widget.cpp history/view/history_view_group_members_widget.h history/view/history_view_item_preview.h history/view/history_view_list_widget.cpp history/view/history_view_list_widget.h history/view/history_view_message.cpp history/view/history_view_message.h history/view/history_view_object.h history/view/history_view_paid_reaction_toast.cpp history/view/history_view_paid_reaction_toast.h history/view/history_view_pinned_bar.cpp history/view/history_view_pinned_bar.h history/view/history_view_pinned_section.cpp history/view/history_view_pinned_section.h history/view/history_view_pinned_tracker.cpp history/view/history_view_pinned_tracker.h history/view/history_view_quick_action.cpp history/view/history_view_quick_action.h history/view/history_view_reaction_preview.cpp history/view/history_view_reaction_preview.h history/view/history_view_read_metrics_tracker.cpp history/view/history_view_read_metrics_tracker.h history/view/history_view_reply.cpp history/view/history_view_reply.h history/view/history_view_reply_button.cpp history/view/history_view_reply_button.h history/view/history_view_requests_bar.cpp history/view/history_view_requests_bar.h history/view/history_view_schedule_box.cpp history/view/history_view_schedule_box.h history/view/history_view_scheduled_section.cpp history/view/history_view_scheduled_section.h history/view/history_view_self_forwards_tagger.cpp history/view/history_view_self_forwards_tagger.h history/view/history_view_send_action.cpp history/view/history_view_send_action.h history/view/history_view_service_message.cpp history/view/history_view_service_message.h history/view/history_view_sponsored_click_handler.cpp history/view/history_view_sponsored_click_handler.h history/view/history_view_sticker_toast.cpp history/view/history_view_sticker_toast.h history/view/history_view_subsection_tabs.cpp history/view/history_view_subsection_tabs.h history/view/history_view_summary_header.cpp history/view/history_view_summary_header.h history/view/history_view_text_helper.cpp history/view/history_view_text_helper.h history/view/history_view_transcribe_button.cpp history/view/history_view_transcribe_button.h history/view/history_view_translate_bar.cpp history/view/history_view_translate_bar.h history/view/history_view_translate_tracker.cpp history/view/history_view_translate_tracker.h history/view/history_view_top_bar_widget.cpp history/view/history_view_top_bar_widget.h history/view/history_view_view_button.cpp history/view/history_view_view_button.h history/view/history_view_webpage_preview.cpp history/view/history_view_webpage_preview.h history/history.cpp history/history.h history/history_drag_area.cpp history/history_drag_area.h history/history_item.cpp history/history_item.h history/history_item_components.cpp history/history_item_components.h history/history_item_edition.cpp history/history_item_edition.h history/history_item_helpers.cpp history/history_item_helpers.h history/history_item_reply_markup.cpp history/history_item_reply_markup.h history/history_item_text.cpp history/history_item_text.h history/history_inner_widget.cpp history/history_inner_widget.h history/history_location_manager.cpp history/history_location_manager.h history/history_streamed_drafts.cpp history/history_streamed_drafts.h history/history_translation.cpp history/history_translation.h history/history_unread_things.cpp history/history_unread_things.h history/history_view_highlight_manager.cpp history/history_view_highlight_manager.h history/history_view_swipe_back_session.cpp history/history_view_swipe_back_session.h history/history_widget.cpp history/history_widget.h info/bot/earn/info_bot_earn_list.cpp info/bot/earn/info_bot_earn_list.h info/bot/earn/info_bot_earn_widget.cpp info/bot/earn/info_bot_earn_widget.h info/bot/starref/info_bot_starref_common.cpp info/bot/starref/info_bot_starref_common.h info/bot/starref/info_bot_starref_join_widget.cpp info/bot/starref/info_bot_starref_join_widget.h info/bot/starref/info_bot_starref_setup_widget.cpp info/bot/starref/info_bot_starref_setup_widget.h info/channel_statistics/boosts/create_giveaway_box.cpp info/channel_statistics/boosts/create_giveaway_box.h info/channel_statistics/boosts/giveaway/giveaway_list_controllers.cpp info/channel_statistics/boosts/giveaway/giveaway_list_controllers.h info/channel_statistics/boosts/info_boosts_inner_widget.cpp info/channel_statistics/boosts/info_boosts_inner_widget.h info/channel_statistics/boosts/info_boosts_widget.cpp info/channel_statistics/boosts/info_boosts_widget.h info/channel_statistics/earn/info_channel_earn_list.cpp info/channel_statistics/earn/info_channel_earn_list.h info/channel_statistics/earn/info_channel_earn_widget.cpp info/channel_statistics/earn/info_channel_earn_widget.h info/common_groups/info_common_groups_inner_widget.cpp info/common_groups/info_common_groups_inner_widget.h info/common_groups/info_common_groups_widget.cpp info/common_groups/info_common_groups_widget.h info/downloads/info_downloads_inner_widget.cpp info/downloads/info_downloads_inner_widget.h info/downloads/info_downloads_provider.cpp info/downloads/info_downloads_provider.h info/downloads/info_downloads_widget.cpp info/downloads/info_downloads_widget.h info/global_media/info_global_media_widget.cpp info/global_media/info_global_media_widget.h info/global_media/info_global_media_inner_widget.cpp info/global_media/info_global_media_inner_widget.h info/global_media/info_global_media_provider.cpp info/global_media/info_global_media_provider.h info/media/info_media_buttons.cpp info/media/info_media_buttons.h info/media/info_media_common.cpp info/media/info_media_common.h info/media/info_media_empty_widget.cpp info/media/info_media_empty_widget.h info/media/info_media_inner_widget.cpp info/media/info_media_inner_widget.h info/media/info_media_list_section.cpp info/media/info_media_list_section.h info/media/info_media_list_widget.cpp info/media/info_media_list_widget.h info/media/info_media_provider.cpp info/media/info_media_provider.h info/media/info_media_widget.cpp info/media/info_media_widget.h info/members/info_members_widget.cpp info/members/info_members_widget.h info/peer_gifts/info_peer_gifts_collections.cpp info/peer_gifts/info_peer_gifts_collections.h info/peer_gifts/info_peer_gifts_common.cpp info/peer_gifts/info_peer_gifts_common.h info/peer_gifts/info_peer_gifts_widget.cpp info/peer_gifts/info_peer_gifts_widget.h info/polls/info_polls_list_widget.cpp info/polls/info_polls_list_widget.h info/polls/info_polls_results_inner_widget.cpp info/polls/info_polls_results_inner_widget.h info/polls/info_polls_results_widget.cpp info/polls/info_polls_results_widget.h info/profile/info_profile_actions.cpp info/profile/info_profile_actions.h info/profile/info_profile_badge_tooltip.cpp info/profile/info_profile_badge_tooltip.h info/profile/info_profile_badge.cpp info/profile/info_profile_badge.h info/profile/info_profile_cover.cpp info/profile/info_profile_cover.h info/profile/info_profile_emoji_status_panel.cpp info/profile/info_profile_emoji_status_panel.h info/profile/info_profile_inner_widget.cpp info/profile/info_profile_inner_widget.h info/profile/info_profile_members.cpp info/profile/info_profile_members.h info/profile/info_profile_members_controllers.cpp info/profile/info_profile_members_controllers.h info/profile/info_profile_phone_menu.cpp info/profile/info_profile_phone_menu.h info/profile/info_profile_status_label.cpp info/profile/info_profile_status_label.h info/profile/info_profile_top_bar.cpp info/profile/info_profile_top_bar.h info/profile/info_profile_values.cpp info/profile/info_profile_values.h info/profile/info_profile_widget.cpp info/profile/info_profile_widget.h info/reactions_list/info_reactions_list_widget.cpp info/reactions_list/info_reactions_list_widget.h info/requests_list/info_requests_list_widget.cpp info/requests_list/info_requests_list_widget.h info/saved/info_saved_music_common.cpp info/saved/info_saved_music_common.h info/saved/info_saved_music_provider.cpp info/saved/info_saved_music_provider.h info/saved/info_saved_music_widget.cpp info/saved/info_saved_music_widget.h info/saved/info_saved_sublists_widget.cpp info/saved/info_saved_sublists_widget.h info/settings/info_settings_widget.cpp info/settings/info_settings_widget.h info/similar_peers/info_similar_peers_widget.cpp info/similar_peers/info_similar_peers_widget.h info/statistics/info_statistics_common.h info/statistics/info_statistics_inner_widget.cpp info/statistics/info_statistics_inner_widget.h info/statistics/info_statistics_list_controllers.cpp info/statistics/info_statistics_list_controllers.h info/statistics/info_statistics_recent_message.cpp info/statistics/info_statistics_recent_message.h info/statistics/info_statistics_tag.h info/statistics/info_statistics_widget.cpp info/statistics/info_statistics_widget.h info/stories/info_stories_albums.cpp info/stories/info_stories_albums.h info/stories/info_stories_common.h info/stories/info_stories_inner_widget.cpp info/stories/info_stories_inner_widget.h info/stories/info_stories_provider.cpp info/stories/info_stories_provider.h info/stories/info_stories_widget.cpp info/stories/info_stories_widget.h info/userpic/info_userpic_colors_editor.cpp info/userpic/info_userpic_colors_editor.h info/userpic/info_userpic_emoji_builder.cpp info/userpic/info_userpic_emoji_builder.h info/userpic/info_userpic_emoji_builder_common.cpp info/userpic/info_userpic_emoji_builder_common.h info/userpic/info_userpic_emoji_builder_menu_item.cpp info/userpic/info_userpic_emoji_builder_menu_item.h info/userpic/info_userpic_emoji_builder_preview.cpp info/userpic/info_userpic_emoji_builder_preview.h info/userpic/info_userpic_emoji_builder_widget.cpp info/userpic/info_userpic_emoji_builder_widget.h info/info_content_widget.cpp info/info_content_widget.h info/info_controller.cpp info/info_controller.h info/info_layer_widget.cpp info/info_layer_widget.h info/info_memento.cpp info/info_memento.h info/info_section_widget.cpp info/info_section_widget.h info/info_top_bar.cpp info/info_top_bar.h info/info_wrap_widget.cpp info/info_wrap_widget.h inline_bots/bot_attach_web_view.cpp inline_bots/bot_attach_web_view.h inline_bots/inline_bot_confirm_prepared.cpp inline_bots/inline_bot_confirm_prepared.h inline_bots/inline_bot_downloads.cpp inline_bots/inline_bot_downloads.h inline_bots/inline_bot_layout_internal.cpp inline_bots/inline_bot_layout_internal.h inline_bots/inline_bot_layout_item.cpp inline_bots/inline_bot_layout_item.h inline_bots/inline_bot_result.cpp inline_bots/inline_bot_result.h inline_bots/inline_bot_send_data.cpp inline_bots/inline_bot_send_data.h inline_bots/inline_bot_storage.cpp inline_bots/inline_bot_storage.h inline_bots/inline_results_inner.cpp inline_bots/inline_results_inner.h inline_bots/inline_results_widget.cpp inline_bots/inline_results_widget.h intro/intro_code.cpp intro/intro_code.h intro/intro_email.cpp intro/intro_email.h intro/intro_password_check.cpp intro/intro_password_check.h intro/intro_phone.cpp intro/intro_phone.h intro/intro_qr.cpp intro/intro_qr.h intro/intro_signup.cpp intro/intro_signup.h intro/intro_start.cpp intro/intro_start.h intro/intro_step.cpp intro/intro_step.h intro/intro_widget.cpp intro/intro_widget.h iv/iv_delegate_impl.cpp iv/iv_delegate_impl.h iv/iv_instance.cpp iv/iv_instance.h lang/lang_cloud_manager.cpp lang/lang_cloud_manager.h lang/lang_instance.cpp lang/lang_instance.h lang/lang_numbers_animation.cpp lang/lang_numbers_animation.h lang/lang_translator.cpp lang/lang_translator.h lang/translate_mtproto_provider.cpp lang/translate_mtproto_provider.h lang/translate_provider.cpp lang/translate_provider.h lang/translate_url_provider.cpp lang/translate_url_provider.h layout/layout_document_generic_preview.cpp layout/layout_document_generic_preview.h layout/layout_item_base.cpp layout/layout_item_base.h main/main_account.cpp main/main_account.h main/main_app_config.cpp main/main_app_config.h main/main_app_config_values.cpp main/main_app_config_values.h main/main_domain.cpp main/main_domain.h main/main_session.cpp main/main_session.h main/main_session_settings.cpp main/main_session_settings.h main/session/send_as_peers.cpp main/session/send_as_peers.h main/session/session_show.cpp main/session/session_show.h media/audio/media_audio.cpp media/audio/media_audio.h media/audio/media_audio_edit.cpp media/audio/media_audio_edit.h media/audio/media_audio_capture.cpp media/audio/media_audio_capture.h media/audio/media_audio_capture_common.h media/audio/media_audio_ffmpeg_loader.cpp media/audio/media_audio_ffmpeg_loader.h media/audio/media_audio_loader.cpp media/audio/media_audio_loader.h media/audio/media_audio_loaders.cpp media/audio/media_audio_loaders.h media/audio/media_audio_local_cache.cpp media/audio/media_audio_local_cache.h media/audio/media_audio_track.cpp media/audio/media_audio_track.h media/audio/media_child_ffmpeg_loader.cpp media/audio/media_child_ffmpeg_loader.h media/player/media_player_float.cpp media/player/media_player_float.h media/player/media_player_instance.cpp media/player/media_player_instance.h media/player/media_player_listen_tracker.cpp media/player/media_player_listen_tracker.h media/player/media_player_panel.cpp media/player/media_player_panel.h media/player/media_player_volume_controller.cpp media/player/media_player_volume_controller.h media/player/media_player_widget.cpp media/player/media_player_widget.h media/stories/media_stories_caption_full_view.cpp media/stories/media_stories_caption_full_view.h media/stories/media_stories_controller.cpp media/stories/media_stories_controller.h media/stories/media_stories_delegate.cpp media/stories/media_stories_delegate.h media/stories/media_stories_header.cpp media/stories/media_stories_header.h media/stories/media_stories_reactions.cpp media/stories/media_stories_reactions.h media/stories/media_stories_recent_views.cpp media/stories/media_stories_recent_views.h media/stories/media_stories_reply.cpp media/stories/media_stories_reply.h media/stories/media_stories_repost_view.cpp media/stories/media_stories_repost_view.h media/stories/media_stories_share.cpp media/stories/media_stories_share.h media/stories/media_stories_sibling.cpp media/stories/media_stories_sibling.h media/stories/media_stories_slider.cpp media/stories/media_stories_slider.h media/stories/media_stories_stealth.cpp media/stories/media_stories_stealth.h media/stories/media_stories_view.cpp media/stories/media_stories_view.h media/streaming/media_streaming_audio_track.cpp media/streaming/media_streaming_audio_track.h media/streaming/media_streaming_common.h media/streaming/media_streaming_document.cpp media/streaming/media_streaming_document.h media/streaming/media_streaming_file.cpp media/streaming/media_streaming_file.h media/streaming/media_streaming_file_delegate.h media/streaming/media_streaming_instance.cpp media/streaming/media_streaming_instance.h media/streaming/media_streaming_loader.cpp media/streaming/media_streaming_loader.h media/streaming/media_streaming_loader_local.cpp media/streaming/media_streaming_loader_local.h media/streaming/media_streaming_loader_mtproto.cpp media/streaming/media_streaming_loader_mtproto.h media/streaming/media_streaming_player.cpp media/streaming/media_streaming_player.h media/streaming/media_streaming_reader.cpp media/streaming/media_streaming_reader.h media/streaming/media_streaming_round_preview.cpp media/streaming/media_streaming_round_preview.h media/streaming/media_streaming_utility.cpp media/streaming/media_streaming_utility.h media/streaming/media_streaming_video_track.cpp media/streaming/media_streaming_video_track.h media/view/media_view_group_thumbs.cpp media/view/media_view_group_thumbs.h media/view/media_view_open_common.cpp media/view/media_view_open_common.h media/view/media_view_overlay_opengl.cpp media/view/media_view_overlay_opengl.h media/view/media_view_overlay_raster.cpp media/view/media_view_overlay_raster.h media/view/media_view_overlay_rhi.cpp media/view/media_view_overlay_rhi.h media/view/media_view_metal_texture.h media/view/media_view_overlay_renderer.h media/view/media_view_overlay_widget.cpp media/view/media_view_overlay_widget.h media/view/media_view_pip.cpp media/view/media_view_pip.h media/view/media_view_pip_opengl.cpp media/view/media_view_pip_opengl.h media/view/media_view_pip_raster.cpp media/view/media_view_pip_raster.h media/view/media_view_pip_rhi.cpp media/view/media_view_pip_rhi.h media/view/media_view_pip_renderer.h media/view/media_view_playback_controls.cpp media/view/media_view_playback_controls.h media/view/media_view_playback_progress.cpp media/view/media_view_playback_progress.h media/view/media_view_playback_sponsored.cpp media/view/media_view_playback_sponsored.h media/view/media_view_video_stream.cpp media/view/media_view_video_stream.h media/system_media_controls_manager.h media/system_media_controls_manager.cpp menu/menu_antispam_validator.cpp menu/menu_antispam_validator.h menu/menu_dock.cpp menu/menu_dock.h menu/menu_item_download_files.cpp menu/menu_item_download_files.h menu/menu_item_rate_transcribe_session.cpp menu/menu_item_rate_transcribe_session.h menu/menu_mute.cpp menu/menu_mute.h menu/menu_send.cpp menu/menu_send.h menu/menu_sponsored.cpp menu/menu_sponsored.h menu/menu_ttl_validator.cpp menu/menu_ttl_validator.h mtproto/config_loader.cpp mtproto/config_loader.h mtproto/connection_abstract.cpp mtproto/connection_abstract.h mtproto/connection_http.cpp mtproto/connection_http.h mtproto/connection_resolving.cpp mtproto/connection_resolving.h mtproto/connection_tcp.cpp mtproto/connection_tcp.h mtproto/core_types.h mtproto/dedicated_file_loader.cpp mtproto/dedicated_file_loader.h mtproto/facade.cpp mtproto/facade.h mtproto/mtp_instance.cpp mtproto/mtp_instance.h mtproto/sender.h mtproto/session.cpp mtproto/session.h mtproto/session_private.cpp mtproto/session_private.h mtproto/special_config_request.cpp mtproto/special_config_request.h mtproto/type_utils.h overview/overview_checkbox.cpp overview/overview_checkbox.h overview/overview_layout.cpp overview/overview_layout.h overview/overview_layout_delegate.h poll/poll_media_upload.cpp poll/poll_media_upload.h passport/passport_encryption.cpp passport/passport_encryption.h passport/passport_form_controller.cpp passport/passport_form_controller.h passport/passport_form_view_controller.cpp passport/passport_form_view_controller.h passport/passport_panel.cpp passport/passport_panel.h passport/passport_panel_controller.cpp passport/passport_panel_controller.h passport/passport_panel_edit_contact.cpp passport/passport_panel_edit_contact.h passport/passport_panel_edit_document.cpp passport/passport_panel_edit_document.h passport/passport_panel_edit_scans.cpp passport/passport_panel_edit_scans.h passport/passport_panel_form.cpp passport/passport_panel_form.h passport/passport_panel_password.cpp passport/passport_panel_password.h payments/payments_checkout_process.cpp payments/payments_checkout_process.h payments/payments_form.cpp payments/payments_form.h payments/payments_non_panel_process.cpp payments/payments_non_panel_process.h payments/payments_reaction_process.cpp payments/payments_reaction_process.h platform/linux/file_utilities_linux.cpp platform/linux/file_utilities_linux.h platform/linux/launcher_linux.cpp platform/linux/launcher_linux.h platform/linux/integration_linux.cpp platform/linux/integration_linux.h platform/linux/main_window_linux.cpp platform/linux/main_window_linux.h platform/linux/notifications_manager_linux.cpp platform/linux/notifications_manager_linux.h platform/linux/overlay_widget_linux.h platform/linux/specific_linux.cpp platform/linux/specific_linux.h platform/linux/translate_provider_linux.cpp platform/linux/translate_provider_linux.h platform/linux/tray_linux.cpp platform/linux/tray_linux.h platform/linux/webauthn_linux.cpp platform/mac/file_utilities_mac.mm platform/mac/file_utilities_mac.h platform/mac/launcher_mac.mm platform/mac/launcher_mac.h platform/mac/integration_mac.mm platform/mac/integration_mac.h platform/mac/mac_iconv_helper.c platform/mac/main_window_mac.mm platform/mac/main_window_mac.h platform/mac/notifications_manager_mac.mm platform/mac/notifications_manager_mac.h platform/mac/overlay_widget_mac.h platform/mac/overlay_widget_mac.mm platform/mac/specific_mac.mm platform/mac/specific_mac.h platform/mac/specific_mac_p.mm platform/mac/specific_mac_p.h platform/mac/translate_provider_mac.h platform/mac/translate_provider_mac.mm platform/mac/tray_mac.h platform/mac/tray_mac.mm platform/mac/webauthn_mac.mm platform/mac/window_title_mac.mm platform/mac/touchbar/items/mac_formatter_item.h platform/mac/touchbar/items/mac_formatter_item.mm platform/mac/touchbar/items/mac_pinned_chats_item.h platform/mac/touchbar/items/mac_pinned_chats_item.mm platform/mac/touchbar/items/mac_scrubber_item.h platform/mac/touchbar/items/mac_scrubber_item.mm platform/mac/touchbar/mac_touchbar_audio.h platform/mac/touchbar/mac_touchbar_audio.mm platform/mac/touchbar/mac_touchbar_common.h platform/mac/touchbar/mac_touchbar_common.mm platform/mac/touchbar/mac_touchbar_controls.h platform/mac/touchbar/mac_touchbar_controls.mm platform/mac/touchbar/mac_touchbar_main.h platform/mac/touchbar/mac_touchbar_main.mm platform/mac/touchbar/mac_touchbar_manager.h platform/mac/touchbar/mac_touchbar_manager.mm platform/mac/touchbar/mac_touchbar_media_view.h platform/mac/touchbar/mac_touchbar_media_view.mm platform/win/file_utilities_win.cpp platform/win/file_utilities_win.h platform/win/launcher_win.cpp platform/win/launcher_win.h platform/win/integration_win.cpp platform/win/integration_win.h platform/win/main_window_win.cpp platform/win/main_window_win.h platform/win/notifications_manager_win.cpp platform/win/notifications_manager_win.h platform/win/overlay_widget_win.h platform/win/specific_win.cpp platform/win/specific_win.h platform/win/translate_provider_win.h platform/win/tray_win.cpp platform/win/tray_win.h platform/win/webauthn_win.cpp platform/win/windows_app_user_model_id.cpp platform/win/windows_app_user_model_id.h platform/win/windows_dlls.cpp platform/win/windows_dlls.h platform/win/windows_autostart_task.cpp platform/win/windows_autostart_task.h platform/win/windows_toast_activator.cpp platform/win/windows_toast_activator.h platform/platform_file_utilities.h platform/platform_launcher.h platform/platform_integration.cpp platform/platform_integration.h platform/platform_main_window.h platform/platform_notifications_manager.h platform/platform_overlay_widget.cpp platform/platform_overlay_widget.h platform/platform_specific.h platform/platform_translate_provider.h platform/platform_tray.h platform/platform_webauthn.h platform/platform_window_title.h profile/profile_block_widget.cpp profile/profile_block_widget.h profile/profile_cover_drop_area.cpp profile/profile_cover_drop_area.h settings/business/settings_away_message.cpp settings/business/settings_away_message.h settings/business/settings_shortcut_messages.cpp settings/business/settings_shortcut_messages.h settings/business/settings_chat_intro.cpp settings/business/settings_chat_intro.h settings/business/settings_chat_links.cpp settings/business/settings_chat_links.h settings/business/settings_chatbots.cpp settings/business/settings_chatbots.h settings/business/settings_greeting.cpp settings/business/settings_greeting.h settings/business/settings_location.cpp settings/business/settings_location.h settings/business/settings_quick_replies.cpp settings/business/settings_quick_replies.h settings/business/settings_recipients_helper.cpp settings/business/settings_recipients_helper.h settings/business/settings_working_hours.cpp settings/business/settings_working_hours.h settings/cloud_password/settings_cloud_password_email.cpp settings/cloud_password/settings_cloud_password_email.h settings/cloud_password/settings_cloud_password_email_confirm.cpp settings/cloud_password/settings_cloud_password_email_confirm.h settings/cloud_password/settings_cloud_password_hint.cpp settings/cloud_password/settings_cloud_password_hint.h settings/cloud_password/settings_cloud_password_input.cpp settings/cloud_password/settings_cloud_password_input.h settings/cloud_password/settings_cloud_password_login_email.cpp settings/cloud_password/settings_cloud_password_login_email.h settings/cloud_password/settings_cloud_password_login_email_confirm.cpp settings/cloud_password/settings_cloud_password_login_email_confirm.h settings/cloud_password/settings_cloud_password_manage.cpp settings/cloud_password/settings_cloud_password_manage.h settings/cloud_password/settings_cloud_password_start.cpp settings/cloud_password/settings_cloud_password_start.h settings/cloud_password/settings_cloud_password_step.cpp settings/cloud_password/settings_cloud_password_step.h settings/cloud_password/settings_cloud_password_validate_icon.cpp settings/cloud_password/settings_cloud_password_validate_icon.h settings/sections/settings_active_sessions.cpp settings/sections/settings_active_sessions.h settings/sections/settings_advanced.cpp settings/sections/settings_advanced.h settings/sections/settings_chat.cpp settings/sections/settings_chat.h settings/sections/settings_blocked_peers.cpp settings/sections/settings_blocked_peers.h settings/sections/settings_business.cpp settings/sections/settings_business.h settings/sections/settings_calls.cpp settings/sections/settings_calls.h settings/sections/settings_fork.cpp settings/sections/settings_fork.h settings/sections/settings_link_device.cpp settings/sections/settings_link_device.h settings/settings_codes.cpp settings/settings_codes.h settings/settings_common_session.cpp settings/settings_common_session.h settings/detailed_settings_button.cpp settings/detailed_settings_button.h settings/sections/settings_credits.cpp settings/sections/settings_credits.h settings/settings_credits_graphics.cpp settings/settings_credits_graphics.h settings/settings_experimental.cpp settings/settings_experimental.h settings/sections/settings_folders.cpp settings/sections/settings_folders.h settings/sections/settings_fork.cpp settings/sections/settings_fork.h settings/sections/settings_global_ttl.cpp settings/sections/settings_global_ttl.h settings/sections/settings_information.cpp settings/sections/settings_information.h settings/settings_intro.cpp settings/settings_intro.h settings/sections/settings_local_passcode.cpp settings/sections/settings_local_passcode.h settings/sections/settings_main.cpp settings/sections/settings_main.h settings/settings_recent_searches.cpp settings/settings_recent_searches.h settings/settings_search.cpp settings/settings_search.h settings/settings_faq_suggestions.cpp settings/settings_faq_suggestions.h settings/settings_builder.cpp settings/settings_builder.h settings/sections/settings_notifications.cpp settings/sections/settings_notifications.h settings/sections/settings_privacy_security.cpp settings/sections/settings_privacy_security.h settings/sections/settings_notifications_reactions.cpp settings/sections/settings_notifications_reactions.h settings/sections/settings_notifications_type.cpp settings/sections/settings_notifications_type.h settings/sections/settings_passkeys.cpp settings/sections/settings_passkeys.h settings/settings_power_saving.cpp settings/settings_power_saving.h settings/sections/settings_premium.cpp settings/sections/settings_premium.h settings/settings_privacy_controllers.cpp settings/settings_privacy_controllers.h settings/settings_scale_preview.cpp settings/settings_scale_preview.h settings/settings_type.h settings/sections/settings_shortcuts.cpp settings/sections/settings_shortcuts.h settings/sections/settings_websites.cpp settings/sections/settings_websites.h storage/details/storage_file_utilities.cpp storage/details/storage_file_utilities.h storage/details/storage_settings_scheme.cpp storage/details/storage_settings_scheme.h storage/download_manager_mtproto.cpp storage/download_manager_mtproto.h storage/file_download.cpp storage/file_download.h storage/file_download_mtproto.cpp storage/file_download_mtproto.h storage/file_download_web.cpp storage/file_download_web.h storage/file_upload.cpp storage/file_upload.h storage/localimageloader.cpp storage/localimageloader.h storage/localstorage.cpp storage/localstorage.h storage/serialize_common.cpp storage/serialize_common.h storage/serialize_document.cpp storage/serialize_document.h storage/serialize_peer.cpp storage/serialize_peer.h storage/storage_account.cpp storage/storage_account.h storage/storage_cloud_blob.cpp storage/storage_cloud_blob.h storage/storage_domain.cpp storage/storage_domain.h storage/storage_facade.cpp storage/storage_facade.h storage/storage_media_prepare.cpp storage/storage_media_prepare.h storage/storage_shared_media.cpp storage/storage_shared_media.h storage/storage_sparse_ids_list.cpp storage/storage_sparse_ids_list.h storage/storage_user_photos.cpp storage/storage_user_photos.h storage/streamed_file_downloader.cpp storage/streamed_file_downloader.h support/support_autocomplete.cpp support/support_autocomplete.h support/support_common.cpp support/support_common.h support/support_helper.cpp support/support_helper.h support/support_preload.cpp support/support_preload.h support/support_templates.cpp support/support_templates.h tde2e/tde2e_integration.cpp tde2e/tde2e_integration.h ui/boxes/edit_invite_link_session.cpp ui/boxes/edit_invite_link_session.h ui/boxes/emoji_stake_box.cpp ui/boxes/emoji_stake_box.h ui/boxes/peer_qr_box.cpp ui/boxes/peer_qr_box.h ui/chat/attach/attach_item_single_file_preview.cpp ui/chat/attach/attach_item_single_file_preview.h ui/chat/attach/attach_item_single_media_preview.cpp ui/chat/attach/attach_item_single_media_preview.h ui/chat/choose_send_as.cpp ui/chat/choose_send_as.h ui/chat/choose_theme_controller.cpp ui/chat/choose_theme_controller.h ui/chat/sponsored_message_bar.cpp ui/chat/sponsored_message_bar.h ui/controls/compose_ai_button_factory.cpp ui/controls/compose_ai_button_factory.h ui/controls/emoji_button_factory.cpp ui/controls/emoji_button_factory.h ui/controls/location_picker.cpp ui/controls/location_picker.h ui/controls/silent_toggle.cpp ui/controls/silent_toggle.h ui/controls/table_rows.cpp ui/controls/table_rows.h ui/controls/userpic_button.cpp ui/controls/userpic_button.h ui/effects/credits_graphics.cpp ui/effects/credits_graphics.h ui/effects/emoji_fly_animation.cpp ui/effects/emoji_fly_animation.h ui/effects/message_sending_animation_common.h ui/effects/message_sending_animation_controller.cpp ui/effects/message_sending_animation_controller.h ui/effects/reaction_fly_animation.cpp ui/effects/reaction_fly_animation.h ui/effects/thanos_effect.cpp ui/effects/thanos_effect.h ui/effects/thanos_effect_controller.cpp ui/effects/thanos_effect_controller.h ui/effects/thanos_effect_renderer.cpp ui/effects/thanos_effect_renderer.h ui/effects/thanos_effect_session.cpp ui/effects/thanos_effect_session.h ui/effects/send_action_animations.cpp ui/effects/send_action_animations.h ui/image/image.cpp ui/image/image.h ui/image/image_location.cpp ui/image/image_location.h ui/image/image_location_factory.cpp ui/image/image_location_factory.h ui/text/format_song_document_name.cpp ui/text/format_song_document_name.h ui/widgets/expandable_peer_list.cpp ui/widgets/expandable_peer_list.h ui/widgets/chat_filters_tabs_strip.cpp ui/widgets/chat_filters_tabs_strip.h ui/widgets/peer_bubble.cpp ui/widgets/peer_bubble.h ui/countryinput.cpp ui/countryinput.h ui/dynamic_thumbnails.cpp ui/dynamic_thumbnails.h ui/filter_icons.cpp ui/filter_icons.h ui/filter_icon_panel.cpp ui/filter_icon_panel.h ui/item_text_options.cpp ui/item_text_options.h ui/resize_area.h ui/top_background_gradient.cpp ui/top_background_gradient.h ui/unread_badge.cpp ui/unread_badge.h ui/peer/video_userpic_player.cpp ui/peer/video_userpic_player.h window/main_window.cpp window/main_window.h window/notifications_manager.cpp window/notifications_manager.h window/notifications_manager_default.cpp window/notifications_manager_default.h window/notifications_utilities.cpp window/notifications_utilities.h window/section_memento.h window/section_widget.cpp window/section_widget.h window/window_adaptive.cpp window/window_adaptive.h window/window_chat_preview.cpp window/window_chat_preview.h window/window_chat_switch_process.cpp window/window_chat_switch_process.h window/window_connecting_widget.cpp window/window_connecting_widget.h window/window_controller.cpp window/window_controller.h window/window_filters_menu.cpp window/window_filters_menu.h window/window_history_hider.cpp window/window_history_hider.h window/window_lock_widgets.cpp window/window_lock_widgets.h window/window_main_menu.cpp window/window_main_menu.h window/window_main_menu_helpers.cpp window/window_main_menu_helpers.h window/window_media_preview.cpp window/window_media_preview.h window/window_peer_menu.cpp window/window_peer_menu.h window/window_section_common.h window/window_separate_id.cpp window/window_separate_id.h window/session/window_session_media.cpp window/window_session_controller.cpp window/window_session_controller.h window/window_session_controller_link_info.h window/window_setup_email.cpp window/window_setup_email.h window/window_top_bar_wrap.h window/themes/window_theme.cpp window/themes/window_theme.h window/themes/window_theme_editor.cpp window/themes/window_theme_editor.h window/themes/window_theme_editor_block.cpp window/themes/window_theme_editor_block.h window/themes/window_theme_editor_box.cpp window/themes/window_theme_editor_box.h window/themes/window_theme_preview.cpp window/themes/window_theme_preview.h window/themes/window_theme_warning.cpp window/themes/window_theme_warning.h window/themes/window_themes_cloud_list.cpp window/themes/window_themes_cloud_list.h window/themes/window_themes_embedded.cpp window/themes/window_themes_embedded.h window/themes/window_themes_generate_name.cpp window/themes/window_themes_generate_name.h apiwrap.cpp apiwrap.h config.h logs.cpp logs.h main.cpp mainwidget.cpp mainwidget.h mainwindow.cpp mainwindow.h settings.cpp settings.h stdafx.h tray_accounts_menu.h tray.cpp tray.h ) if (APPLE) nice_target_sources(Telegram ${src_loc} PRIVATE tray_accounts_menu.cpp media/view/media_view_metal_texture.mm ) else() nice_target_sources(Telegram ${src_loc} PRIVATE tray_accounts_menu_dummy.cpp ) endif() if (NOT build_winstore) remove_target_sources(Telegram ${src_loc} platform/win/windows_start_task.cpp platform/win/windows_start_task.h ) endif() if (DESKTOP_APP_USE_PACKAGED) remove_target_sources(Telegram ${src_loc} platform/mac/mac_iconv_helper.c ) endif() nice_target_sources(Telegram ${res_loc} PRIVATE qrc/emoji_1.qrc qrc/emoji_2.qrc qrc/emoji_3.qrc qrc/emoji_4.qrc qrc/emoji_5.qrc qrc/emoji_6.qrc qrc/emoji_7.qrc qrc/emoji_8.qrc qrc/emoji_preview.qrc qrc/telegram/animations.qrc qrc/telegram/export.qrc qrc/telegram/iv.qrc qrc/telegram/picker.qrc qrc/telegram/telegram.qrc qrc/telegram/sounds.qrc winrc/Telegram.rc winrc/Telegram.manifest langs/lang.strings langs/cloud_lang.strings numbers.txt ) include(cmake/qrhi_shaders.cmake) if (APPLE AND NOT build_macstore) nice_target_sources(Telegram ${res_loc} PRIVATE qrc/telegram/mac_icons.qrc ) endif() if (WIN32) # message(${CMAKE_GENERATOR}) # mt.exe -manifest "${res_loc}/winrc/Telegram.manifest" "-inputresource:\"$\";#1" "-outputresource:\"$\";#1" >NUL # set(hash_symbol "#") # set(release $) # add_custom_command( # TARGET # Telegram # POST_BUILD COMMAND # $ $<${release}:-manifest> $<${release}:"${res_loc}/winrc/Telegram.manifest"> $<${release}:-inputresource:"$"$${hash_symbol}1> $<${release}:-outputresource:"$"$${hash_symbol}1> $<${release}:$NUL> # COMMENT # $ # ) if (QT_VERSION LESS 6) target_link_libraries(Telegram PRIVATE desktop-app::win_directx_helper) endif() target_link_options(Telegram PRIVATE /PDBPAGESIZE:8192) elseif (APPLE) if (NOT DESKTOP_APP_USE_PACKAGED) target_link_libraries(Telegram PRIVATE desktop-app::external_iconv) endif() set(icons_path ${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Images.xcassets) if (CMAKE_GENERATOR STREQUAL Xcode) target_add_resource(Telegram ${icons_path}) else() set(icon_path ${icons_path}/Icon.iconset) find_program(ICONUTIL iconutil) find_program(PNG2ICNS png2icns) if (ICONUTIL) add_custom_command( OUTPUT Icon.icns COMMAND ${ICONUTIL} ARGS --convert icns --output Icon.icns ${icon_path} ) elseif (PNG2ICNS) add_custom_command( OUTPUT Icon.icns COMMAND ${PNG2ICNS} ARGS Icon.icns ${icon_path}/icon_16x16.png ${icon_path}/icon_32x32.png ${icon_path}/icon_128x128.png ${icon_path}/icon_256x256.png ${icon_path}/icon_512x512.png ) endif() if (ICONUTIL OR PNG2ICNS) set_source_files_properties(Icon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) target_add_resource(Telegram Icon.icns) endif() endif() set(lang_packs en de es it nl ko pt-BR ) foreach (lang ${lang_packs}) set(strings_path ${res_loc}/langs/${lang}.lproj/Localizable.strings) set_source_files_properties(${strings_path} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/${lang}.lproj ) target_sources(Telegram PRIVATE ${strings_path}) source_group(TREE ${res_loc} PREFIX Resources FILES ${strings_path}) endforeach() add_custom_command(TARGET Telegram PRE_LINK COMMAND mkdir -p $/../Resources COMMAND cp ${CMAKE_BINARY_DIR}/lib_ui.rcc $/../Resources COMMAND cp ${CMAKE_BINARY_DIR}/lib_spellcheck.rcc $/../Resources ) if (NOT build_macstore AND NOT DESKTOP_APP_DISABLE_CRASH_REPORTS) if (DESKTOP_APP_USE_PACKAGED) find_program(CRASHPAD_HANDLER crashpad_handler REQUIRED) elseif (DESKTOP_APP_MAC_ARCH STREQUAL "x86_64" OR DESKTOP_APP_MAC_ARCH STREQUAL "arm64") set(CRASHPAD_HANDLER "${libs_loc}/crashpad/out/$,Debug,Release>.${DESKTOP_APP_MAC_ARCH}/crashpad_handler") else() set(CRASHPAD_HANDLER "${libs_loc}/crashpad/out/$,Debug,Release>/crashpad_handler") endif() add_custom_command(TARGET Telegram PRE_LINK COMMAND mkdir -p $/../Helpers COMMAND cp ${CRASHPAD_HANDLER} $/../Helpers/ ) endif() else() include(${cmake_helpers_loc}/external/glib/generate_dbus.cmake) generate_dbus(Telegram org.freedesktop.portal. XdpBackground ${third_party_loc}/xdg-desktop-portal/data/org.freedesktop.portal.Background.xml) generate_dbus(Telegram org.freedesktop. XdgNotifications ${src_loc}/platform/linux/org.freedesktop.Notifications.xml) if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION) target_link_libraries(Telegram PRIVATE desktop-app::external_xcb ) endif() endif() if (build_macstore) set(bundle_identifier "org.telegram.desktop") set(bundle_entitlements "Telegram Lite.entitlements") set(output_name "Telegram Lite") target_link_options(Telegram PRIVATE -F${libs_loc}/breakpad/src/client/mac/build/Release ) target_link_frameworks(Telegram PRIVATE Breakpad) add_custom_command(TARGET Telegram PRE_LINK COMMAND rm -rf $/../Frameworks COMMAND mkdir -p $/../Frameworks COMMAND cp -a ${libs_loc}/breakpad/src/client/mac/build/Release/Breakpad.framework $/../Frameworks/Breakpad.framework COMMAND rm -rf $/../Frameworks/Breakpad.framework/Resources/crash_report_sender.app COMMAND rm -rf $/../Frameworks/Breakpad.framework/Resources/Inspector ) else() if (CMAKE_GENERATOR STREQUAL Xcode) set(bundle_identifier "com.tdesktop.Telegram$<$:Debug>") else() set(bundle_identifier "com.tdesktop.Telegram") endif() set(bundle_entitlements "Telegram.entitlements") set(output_name "Telegram") if (LINUX OR APPLE) set(output_name "Forkgram") endif() endif() if (CMAKE_GENERATOR STREQUAL Xcode) set(bundle_identifier_plist "$(PRODUCT_BUNDLE_IDENTIFIER)") else() set(bundle_identifier_plist ${bundle_identifier}) endif() set_target_properties(Telegram PROPERTIES OUTPUT_NAME ${output_name} MACOSX_BUNDLE_GUI_IDENTIFIER ${bundle_identifier} MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Telegram.plist XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/Telegram/${bundle_entitlements}" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${bundle_identifier} XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION ${desktop_app_version_string} XCODE_ATTRIBUTE_PRODUCT_NAME ${output_name} XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AppIcon XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES XCODE_ATTRIBUTE_COMBINE_HIDPI_IMAGES YES XCODE_ATTRIBUTE_COPY_PHASE_STRIP NO XCODE_ATTRIBUTE_ALWAYS_SEARCH_USER_PATHS NO XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY libc++ XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS --deep XCODE_ATTRIBUTE_CLANG_DEBUG_INFORMATION_LEVEL $,default,line-tables-only> ) set(entitlement_sources "${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Telegram.entitlements" "${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Telegram Lite.entitlements" ) target_sources(Telegram PRIVATE ${entitlement_sources}) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/Telegram PREFIX Resources FILES ${entitlement_sources}) target_include_directories(Telegram PRIVATE ${src_loc}) target_compile_definitions(Telegram PRIVATE TDESKTOP_API_ID=${TDESKTOP_API_ID} TDESKTOP_API_HASH=${TDESKTOP_API_HASH} G_LOG_DOMAIN="Telegram" ) get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if (APPLE OR is_multi_config OR NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL "" OR NOT "${output_name}" STREQUAL "Telegram") set(output_folder ${CMAKE_BINARY_DIR}) else() set(output_folder ${CMAKE_BINARY_DIR}/bin) endif() set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder}) if (MSVC) target_link_libraries(Telegram PRIVATE delayimp ) target_link_options(Telegram PRIVATE /DELAYLOAD:secur32.dll /DELAYLOAD:winmm.dll /DELAYLOAD:ws2_32.dll /DELAYLOAD:user32.dll /DELAYLOAD:gdi32.dll /DELAYLOAD:advapi32.dll /DELAYLOAD:avrt.dll /DELAYLOAD:shell32.dll /DELAYLOAD:ole32.dll /DELAYLOAD:oleaut32.dll /DELAYLOAD:shlwapi.dll /DELAYLOAD:iphlpapi.dll /DELAYLOAD:gdiplus.dll /DELAYLOAD:version.dll /DELAYLOAD:dwmapi.dll /DELAYLOAD:uxtheme.dll /DELAYLOAD:crypt32.dll /DELAYLOAD:bcrypt.dll /DELAYLOAD:netapi32.dll /DELAYLOAD:imm32.dll /DELAYLOAD:userenv.dll /DELAYLOAD:wtsapi32.dll /DELAYLOAD:propsys.dll ) if (QT_VERSION GREATER 6) if (NOT build_winarm) target_link_options(Telegram PRIVATE /DELAYLOAD:API-MS-Win-EventLog-Legacy-l1-1-0.dll ) endif() target_link_options(Telegram PRIVATE /DELAYLOAD:API-MS-Win-Core-Console-l1-1-0.dll /DELAYLOAD:API-MS-Win-Core-Fibers-l2-1-0.dll /DELAYLOAD:API-MS-Win-Core-Fibers-l2-1-1.dll /DELAYLOAD:API-MS-Win-Core-File-l1-1-0.dll /DELAYLOAD:API-MS-Win-Core-LibraryLoader-l1-2-0.dll /DELAYLOAD:API-MS-Win-Core-Localization-l1-2-0.dll /DELAYLOAD:API-MS-Win-Core-Memory-l1-1-0.dll /DELAYLOAD:API-MS-Win-Core-Memory-l1-1-1.dll /DELAYLOAD:API-MS-Win-Core-ProcessThreads-l1-1-0.dll /DELAYLOAD:API-MS-Win-Core-Synch-l1-2-0.dll # Synchronization.lib /DELAYLOAD:API-MS-Win-Core-SysInfo-l1-1-0.dll # /DELAYLOAD:API-MS-Win-Core-Timezone-l1-1-0.dll /DELAYLOAD:API-MS-Win-Core-WinRT-l1-1-0.dll /DELAYLOAD:API-MS-Win-Core-WinRT-Error-l1-1-0.dll /DELAYLOAD:API-MS-Win-Core-WinRT-String-l1-1-0.dll /DELAYLOAD:API-MS-Win-Security-CryptoAPI-l1-1-0.dll # /DELAYLOAD:API-MS-Win-Shcore-Scaling-l1-1-1.dll # We shadowed GetDpiForMonitor /DELAYLOAD:authz.dll # Authz.lib /DELAYLOAD:comdlg32.dll /DELAYLOAD:dwrite.dll # DWrite.lib /DELAYLOAD:dxgi.dll # DXGI.lib /DELAYLOAD:d3d9.dll # D3D9.lib /DELAYLOAD:d3d11.dll # D3D11.lib /DELAYLOAD:d3d12.dll # D3D12.lib /DELAYLOAD:setupapi.dll # SetupAPI.lib /DELAYLOAD:winhttp.dll ) endif() endif() target_prepare_qrc(Telegram) if (NOT DESKTOP_APP_DISABLE_AUTOUPDATE AND NOT build_macstore AND NOT build_winstore) add_executable(Updater WIN32) init_non_host_target(Updater) add_dependencies(Telegram Updater) nice_target_sources(Updater ${src_loc} PRIVATE _other/updater_win.cpp _other/updater_linux.cpp _other/updater_osx.m _other/updater.h ) set_target_properties(Updater PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder} ) if (WIN32) get_filename_component(lib_base_loc lib_base REALPATH) nice_target_sources(Updater ${lib_base_loc} PRIVATE base/platform/win/base_windows_safe_library.cpp base/platform/win/base_windows_safe_library.h ) target_include_directories(Updater PRIVATE ${lib_base_loc}) if (MSVC) target_link_libraries(Updater PRIVATE delayimp ) target_link_options(Updater PRIVATE /DELAYLOAD:user32.dll /DELAYLOAD:advapi32.dll /DELAYLOAD:shell32.dll /DELAYLOAD:ole32.dll /DELAYLOAD:shlwapi.dll ) else() target_link_options(Updater PRIVATE -municode) endif() elseif (APPLE) add_custom_command(TARGET Updater POST_BUILD COMMAND mkdir -p $/../Frameworks COMMAND cp $ $/../Frameworks/ ) endif() if (DESKTOP_APP_SPECIAL_TARGET) add_executable(Packer) init_target(Packer) add_dependencies(Telegram Packer) nice_target_sources(Packer ${src_loc} PRIVATE _other/packer.cpp _other/packer.h ) target_link_libraries(Packer PRIVATE desktop-app::external_qt desktop-app::external_zlib desktop-app::external_auto_updates desktop-app::external_openssl ) if (DESKTOP_APP_USE_PACKAGED) target_compile_definitions(Packer PRIVATE PACKER_USE_PACKAGED) endif() set_target_properties(Packer PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder}) endif() elseif (build_winstore) add_executable(StartupTask WIN32) init_non_host_target(StartupTask) add_dependencies(Telegram StartupTask) nice_target_sources(StartupTask ${src_loc} PRIVATE _other/startup_task_win.cpp ) set_target_properties(StartupTask PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder} ) endif() if (LINUX AND DESKTOP_APP_USE_PACKAGED) include(GNUInstallDirs) configure_file("../lib/xdg/org.telegram.desktop.service" "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.service" @ONLY) configure_file("../lib/xdg/org.telegram.desktop.metainfo.xml" "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.metainfo.xml" @ONLY) generate_appstream_changelog(Telegram "${CMAKE_SOURCE_DIR}/changelog.txt" "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.metainfo.xml") install(TARGETS Telegram RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}") install(FILES "Resources/art/icon16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon16@2x.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16@2/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon32@2x.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32@2/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon48@2x.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48@2/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon64@2x.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64@2/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon128@2x.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128@2/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon256@2x.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256@2/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/art/icon512@2x.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512@2/apps" RENAME "io.github.forkgram.tdesktop.png") install(FILES "Resources/icons/tray_monochrome.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/symbolic/apps" RENAME "io.github.forkgram.tdesktop-symbolic.svg") install(FILES "Resources/icons/tray_monochrome_attention.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/symbolic/apps" RENAME "io.github.forkgram.tdesktop-attention-symbolic.svg") install(FILES "Resources/icons/tray_monochrome_mute.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/symbolic/apps" RENAME "io.github.forkgram.tdesktop-mute-symbolic.svg") install(FILES "../lib/xdg/org.telegram.desktop.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications" RENAME "io.github.forkgram.tdesktop.desktop") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.service" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/dbus-1/services" RENAME "io.github.forkgram.tdesktop.service") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.metainfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo" RENAME "io.github.forkgram.tdesktop.metainfo.xml") endif() ================================================ FILE: Telegram/Resources/default_shortcuts-custom.json ================================================ // This is a list of your own shortcuts for Telegram Desktop // You can see full list of commands in the 'shortcuts-default.json' file // Place a null value instead of a command string to switch the shortcut off // You can also edit them in Settings > Chat Settings > Keyboard Shortcuts. [ // { // "command": "close_telegram", // "keys": "ctrl+f4" // }, // { // "command": "quit_telegram", // "keys": "ctrl+q" // } ] ================================================ FILE: Telegram/Resources/export_html/css/style.css ================================================ body { margin: 0; font: 12px/18px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif; } strong { font-weight: 700; } code, kbd, pre, samp { font-family: Menlo,Monaco,Consolas,"Courier New",monospace; } code { padding: 2px 4px; font-size: 90%; color: #c7254e; background-color: #f9f2f4; border-radius: 4px; } pre { display: block; margin: 0; line-height: 1.42857143; word-break: break-all; word-wrap: break-word; color: #333; background-color: #f5f5f5; border-radius: 4px; overflow: auto; padding: 3px; border: 1px solid #eee; max-height: none; font-size: inherit; } .clearfix:after { content: " "; visibility: hidden; display: block; height: 0; clear: both; } .pull_left { float: left; } .pull_right { float: right; } .page_wrap { background-color: #ffffff; color: #000000; } .page_wrap a { color: #168acd; text-decoration: none; } .page_wrap a:hover { text-decoration: underline; } .page_header { position: fixed; z-index: 10; background-color: #ffffff; width: 100%; border-bottom: 1px solid #e3e6e8; } .page_header .content { width: 480px; margin: 0 auto; border-radius: 0 !important; } .page_header a.content { background-repeat: no-repeat; background-position: 24px 21px; background-size: 24px 24px; } .bold { color: #212121; font-weight: 700; } .details { color: #70777b; } .page_header .content .text { padding: 24px 24px 22px 24px; font-size: 22px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .page_header a.content .text { padding: 24px 24px 22px 82px; } .page_body { padding-top: 64px; width: 480px; margin: 0 auto; } .page_about { padding: 24px 24px; } .with_divider { border-top: 1px solid #e3e6e8; } .userpic_link { display: block; text-decoration: none; } .userpic_link:hover { text-decoration: none; } .userpic { display: block; border-radius: 50%; overflow: hidden; } .story { display: block; border-radius: 4px; overflow: hidden; } .userpic .initials { display: block; color: #fff; text-align: center; text-transform: uppercase; user-select: none; } .color_red, .userpic1, .media_call .fill, .media_file .fill, .media_live_location .fill { background-color: #ff5555; } .color_green, .userpic2, .media_call.success .fill, .media_photo .fill { background-color: #64bf47; } .color_yellow, .userpic3, .media_venue .fill { background-color: #ffab00; } .color_blue, .userpic4, .media_audio_file .fill, .media_voice_message .fill { background-color: #4f9cd9; } .color_purple, .userpic5, .media_game .fill { background-color: #9884e8; } .color_pink, .userpic6, .media_invoice .fill { background-color: #e671a5; } .color_sea, .userpic7, .media_location .fill, .media_video .fill { background-color: #47bcd1; } .color_orange, .userpic8, .media_contact .fill { background-color: #ff8c44; } .personal_info { padding: 24px; } .personal_info .userpic .initials { font-size: 30px; } .personal_info .rows { float: left; padding-right: 24px; } .personal_info .names { width: 164px; } .personal_info .info { width: 124px; } .personal_info .bio { width: 400px; } .personal_info .row { padding-bottom: 16px; } a.block_link { display: block; text-decoration: none !important; border-radius: 4px; } a.block_link:hover { text-decoration: none !important; background-color: #f5f7f8; } a.expanded { padding: 2px 8px; margin: -2px -8px; } .sections { padding: 11px 0; } .section { height: 48px; background-position: 24px 12px; background-repeat: no-repeat; background-size: 24px 24px; } .section .counter { float: right; padding: 14px 24px 0; font-size: 15px; } .section .label { padding: 15px 0 0 82px; font-size: 15px; } .list_page .page_about { padding: 16px 24px 0; font-size: 11px; } .list_page .entry_list { padding: 16px 0; } .list_page .entry { padding: 10px 16px; } .list_page .entry .userpic .initials { font-size: 18px; } .list_page .entry .body { margin-left: 66px; } .list_page .entry .name { padding: 4px 0 2px; font-size: 14px; } .list_page .entry .subname { padding-top: 4px; } .list_page .entry .details_entry { padding-top: 4px; } .list_page .entry .info { font-size: 11px; padding-top: 5px; } .history { padding: 16px 0; } .message { margin: 0 -10px; transition: background-color 2.0s ease; } div.selected { background-color: rgba(242,246,250,255); transition: background-color 0.5s ease; } .service { padding: 10px 24px; } .service .body { text-align: center; } .service .userpic_wrap { padding-top: 10px; } .service .userpic { margin: 0 auto; } .service .userpic .initials { font-size: 24px; } .message .userpic .initials { font-size: 16px; } .default { padding: 10px; } .default.joined { margin-top: -10px; } .default .from_name { color: #3892db; font-weight: 700; padding-bottom: 5px; } .default .from_name .details { font-weight: normal; } .default .body { margin-left: 60px; } .default .text { word-wrap: break-word; line-height: 150%; unicode-bidi: plaintext; text-align: start; } .default .reply_to, .default .media_wrap { padding-bottom: 5px; } .default .media { margin: 0 -10px; padding: 5px 10px; } .default .media .fill, .default .media .thumb { width: 48px; height: 48px; border-radius: 50%; } .default .media .fill { background-repeat: no-repeat; background-position: 12px 12px; background-size: 24px 24px; } .default .media .title, .default .media_poll .question { padding-top: 4px; font-size: 14px; } .default .media .description { color: #000000; padding-top: 4px; font-size: 13px; } .default .media .status { padding-top: 4px; font-size: 13px; } .default .video_file_wrap, .default .animated_wrap { position: relative; } .default .video_file, .default .animated, .default .photo, .default .sticker { display: block; } .video_duration { background: rgba(0, 0, 0, .4); padding: 0px 5px; position: absolute; z-index: 2; border-radius: 2px; right: 3px; bottom: 3px; color: #ffffff; font-size: 11px; } .video_play_bg { background: rgba(0, 0, 0, .4); width: 40px; height: 40px; line-height: 0; position: absolute; z-index: 2; border-radius: 50%; overflow: hidden; margin: -20px auto 0 -20px; top: 50%; left: 50%; pointer-events: none; } .video_play { position: absolute; display: inline-block; top: 50%; left: 50%; margin-left: -5px; margin-top: -9px; z-index: 1; width: 0; height: 0; border-style: solid; border-width: 9px 0 9px 14px; border-color: transparent transparent transparent #fff; } .gif_play { font-weight: 700; color: #FFF; display: block; line-height: 40px; font-size: 13px; text-align: center; } .pagination { text-align: center; padding: 20px; font-size: 16px; } .toast_container { position: fixed; left: 50%; top: 50%; opacity: 0; transition: opacity 3.0s ease; } .toast_body { margin: 0 -50%; float: left; border-radius: 15px; padding: 10px 20px; background: rgba(0, 0, 0, 0.7); color: #ffffff; } div.toast_shown { opacity: 1; transition: opacity 0.4s ease; } .section.calls { background-image: url(../images/section_calls.png); } .section.chats { background-image: url(../images/section_chats.png); } .section.contacts { background-image: url(../images/section_contacts.png); } .section.frequent { background-image: url(../images/section_frequent.png); } .section.photos { background-image: url(../images/section_photos.png); } .section.sessions { background-image: url(../images/section_sessions.png); } .section.stories { background-image: url(../images/section_stories.png); } .section.music { background-image: url(../images/section_music.png); } .section.web { background-image: url(../images/section_web.png); } .section.other { background-image: url(../images/section_other.png) } .page_header a.content { background-image: url(../images/back.png); } .media_call .fill { background-image: url(../images/media_call.png) } .media_contact .fill { background-image: url(../images/media_contact.png) } .media_file .fill { background-image: url(../images/media_file.png) } .media_game .fill { background-image: url(../images/media_game.png) } .media_live_location .fill, .media_location .fill, .media_venue .fill { background-image: url(../images/media_location.png) } .media_audio_file .fill { background-image: url(../images/media_music.png) } .media_invoice .fill { background-image: url(../images/media_shop.png) } .media_voice_message .fill { background-image: url(../images/media_voice.png) } .media_photo .fill { background-image: url(../images/media_photo.png) } .media_video .fill { background-image: url(../images/media_video.png) } .audio_icon { width: 48px; height: 48px; border-radius: 50%; background-color: #4f9cd9; background-image: url(../images/media_music.png); background-repeat: no-repeat; background-position: 12px 12px; background-size: 24px 24px; } @media only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) { .section.calls { background-image: url(../images/section_calls@2x.png); } .section.chats { background-image: url(../images/section_chats@2x.png); } .section.contacts { background-image: url(../images/section_contacts@2x.png); } .section.frequent { background-image: url(../images/section_frequent@2x.png); } .section.photos { background-image: url(../images/section_photos@2x.png); } .section.sessions { background-image: url(../images/section_sessions@2x.png); } .section.stories { background-image: url(../images/section_stories@2x.png); } .section.music { background-image: url(../images/section_music@2x.png); } .section.web { background-image: url(../images/section_web@2x.png); } .section.other { background-image: url(../images/section_other@2x.png); } .page_header a.content { background-image: url(../images/back@2x.png); } .media_call .fill { background-image: url(../images/media_call@2x.png) } .media_contact .fill { background-image: url(../images/media_contact@2x.png) } .media_file .fill { background-image: url(../images/media_file@2x.png) } .media_game .fill { background-image: url(../images/media_game@2x.png) } .media_live_location .fill, .media_location .fill, .media_venue .fill { background-image: url(../images/media_location@2x.png) } .media_audio_file .fill { background-image: url(../images/media_music@2x.png) } .media_invoice .fill { background-image: url(../images/media_shop@2x.png) } .media_voice_message .fill { background-image: url(../images/media_voice@2x.png) } .media_photo .fill { background-image: url(../images/media_photo@2x.png) } .media_video .fill { background-image: url(../images/media_video@2x.png) } .audio_icon { background-image: url(../images/media_music@2x.png); } } .spoiler { background: #e8e8e8; } .spoiler.hidden { background: #a9a9a9; cursor: pointer; border-radius: 3px; } .spoiler.hidden span { opacity: 0; user-select: none; } .bot_buttons_table { border-spacing: 0px 2px; width: 100%; } .bot_button { border-radius: 8px; text-align: center; vertical-align: middle; background-color: #168acd40; } .bot_button_row { display: table; table-layout: fixed; padding: 0px; width:100%; } .bot_button_row div { display: table-cell; } .bot_button_column_separator { width: 2px } .reactions { margin: 5px 0; } .reactions .reaction { display: inline-flex; height: 20px; border-radius: 15px; background-color: #e8f5fc; color: #168acd; font-weight: bold; margin-bottom: 5px; } .reactions .reaction.active { background-color: #40a6e2; color: #fff; } .reactions .reaction.paid { background-color: #fdf6e1; color: #c58523; } .reactions .reaction.active.paid { background-color: #ecae0a; color: #fdf6e1; } .reactions .reaction .emoji { line-height: 20px; margin: 0 5px; font-size: 15px; } .reactions .reaction .userpic:not(:first-child) { margin-left: -8px; } .reactions .reaction .userpic { display: inline-block; } .reactions .reaction .userpic .initials { font-size: 8px; } .reactions .reaction .count { margin-right: 8px; line-height: 20px; } @media (prefers-color-scheme: dark) { html, body { background-color: #1a2026; /* groupCallBg */ margin: 0; padding: 0; } .page_wrap { background-color: #1a2026; /* groupCallBg */ color: #ffffff; /* groupCallMembersFg */ min-height: 100vh; } .page_wrap a { color: #4db8ff; /* groupCallActiveFg */ } .page_header { background-color: #1a2026; /* groupCallBg */ border-bottom: 1px solid #2c333d; /* groupCallMembersBg */ } .bold { color: #ffffff; /* groupCallMembersFg */ } .details { color: #91979e; /* groupCallMemberNotJoinedStatus */ } .page_body { background-color: #1a2026; /* groupCallBg */ } code { color: #ff8aac; /* historyPeer6UserpicBg */ background-color: #2c333d; /* groupCallMembersBg */ } pre { color: #ffffff; /* groupCallMembersFg */ background-color: #2c333d; /* groupCallMembersBg */ border: 1px solid #323a45; /* groupCallMembersBgOver */ } .with_divider { border-top: 1px solid #2c333d; /* groupCallMembersBg */ } a.block_link:hover { background-color: #323a45; /* groupCallMembersBgOver */ } .list_page .entry { color: #ffffff; /* groupCallMembersFg */ } .message { color: #ffffff; /* groupCallMembersFg */ } div.selected { background-color: #323a45; /* groupCallMembersBgOver */ } .default .from_name { color: #4db8ff; /* groupCallActiveFg */ } .default .media .description { color: #ffffff; /* groupCallMembersFg */ } msgInBg, .historyComposeAreaBg { background-color: #2c333d; /* groupCallMembersBg */ } msgOutBg { background-color: #323a45; /* groupCallMembersBgOver */ } msgInBgSelected { background-color: #39424f; /* groupCallMembersBgRipple */ } msgOutBgSelected { background-color: #39424f; /* groupCallMembersBgRipple */ } .spoiler { background: #323a45; /* groupCallMembersBgOver */ } .spoiler.hidden { background: #61c0ff; /* groupCallMemberInactiveStatus */ } .bot_button { background-color: #4db8ff40; /* groupCallActiveFg with opacity */ } .reactions .reaction { background-color: #2c333d; /* groupCallMembersBg */ color: #4db8ff; /* groupCallActiveFg */ } .reactions .reaction.active { background-color: #4db8ff; /* groupCallActiveFg */ color: #1a2026; /* groupCallBg */ } .reactions .reaction.paid { background-color: #323a45; /* groupCallMembersBgOver */ color: #febb5b; /* historyPeer8UserpicBg */ } .reactions .reaction.active.paid { background-color: #febb5b; /* historyPeer8UserpicBg */ color: #1a2026; /* groupCallBg */ } } ================================================ FILE: Telegram/Resources/export_html/js/script.js ================================================ "use strict"; window.AllowBackFromHistory = false; function CheckLocation() { var start = "#go_to_message"; var hash = location.hash; if (hash.substr(0, start.length) == start) { var messageId = parseInt(hash.substr(start.length)); if (messageId) { GoToMessage(messageId); } } else if (hash == "#allow_back") { window.AllowBackFromHistory = true; } } function ShowToast(text) { var container = document.createElement("div"); container.className = "toast_container"; var inner = container.appendChild(document.createElement("div")); inner.className = "toast_body"; inner.appendChild(document.createTextNode(text)); var appended = document.body.appendChild(container); setTimeout(function () { AddClass(appended, "toast_shown"); setTimeout(function () { RemoveClass(appended, "toast_shown"); setTimeout(function () { document.body.removeChild(appended); }, 3000); }, 3000); }, 0); } function ShowHashtag(tag) { ShowToast("This is a hashtag '#" + tag + "' link."); return false; } function ShowCashtag(tag) { ShowToast("This is a cashtag '$" + tag + "' link."); return false; } function ShowBotCommand(command) { ShowToast("This is a bot command '/" + command + "' link."); return false; } function ShowMentionName() { ShowToast("This is a link to a user mentioned by name."); return false; } function ShowNotLoadedEmoji() { ShowToast("This custom emoji is not included, change data exporting settings to download."); return false; } function ShowNotAvailableEmoji() { ShowToast("This custom emoji is not available."); return false; } function ShowTextCopied(content) { navigator.clipboard.writeText(content); ShowToast("Text copied to clipboard."); return false; } function ShowSpoiler(target) { if (target.classList.contains("hidden")) { target.classList.toggle("hidden"); } } function AddClass(element, name) { var current = element.className; var expression = new RegExp('(^|\\s)' + name + '(\\s|$)', 'g'); if (expression.test(current)) { return; } element.className = current + ' ' + name; } function RemoveClass(element, name) { var current = element.className; var expression = new RegExp('(^|\\s)' + name + '(\\s|$)', ''); var match = expression.exec(current); while ((match = expression.exec(current)) != null) { if (match[1].length > 0 && match[2].length > 0) { current = current.substr(0, match.index + match[1].length) + current.substr(match.index + match[0].length); } else { current = current.substr(0, match.index) + current.substr(match.index + match[0].length); } } element.className = current; } function EaseOutQuad(t) { return t * t; } function EaseInOutQuad(t) { return (t < 0.5) ? (2 * t * t) : ((4 - 2 * t) * t - 1); } function ScrollHeight() { if ("innerHeight" in window) { return window.innerHeight; } else if (document.documentElement) { return document.documentElement.clientHeight; } return document.body.clientHeight; } function ScrollTo(top, callback) { var html = document.documentElement; var current = html.scrollTop; var delta = top - current; var finish = function () { html.scrollTop = top; if (callback) { callback(); } }; if (!window.performance.now || delta == 0) { finish(); return; } var transition = EaseOutQuad; var max = 300; if (delta < -max) { current = top + max; delta = -max; } else if (delta > max) { current = top - max; delta = max; } else { transition = EaseInOutQuad; } var duration = 150; var interval = 7; var time = window.performance.now(); var animate = function () { var now = window.performance.now(); if (now >= time + duration) { finish(); return; } var dt = (now - time) / duration; html.scrollTop = Math.round(current + delta * transition(dt)); setTimeout(animate, interval); }; setTimeout(animate, interval); } function ScrollToElement(element, callback) { var header = document.getElementsByClassName("page_header")[0]; var headerHeight = header.offsetHeight; var html = document.documentElement; var scrollHeight = ScrollHeight(); var available = scrollHeight - headerHeight; var padding = 10; var top = element.offsetTop; var height = element.offsetHeight; var desired = top - Math.max((available - height) / 2, padding) - headerHeight; var scrollTopMax = html.offsetHeight - scrollHeight; ScrollTo(Math.min(desired, scrollTopMax), callback); } function GoToMessage(messageId) { var element = document.getElementById("message" + messageId); if (element) { var hash = "#go_to_message" + messageId; if (location.hash != hash) { location.hash = hash; } ScrollToElement(element, function () { AddClass(element, "selected"); setTimeout(function () { RemoveClass(element, "selected"); }, 1000); }); } else { ShowToast("This message was not exported. Maybe it was deleted."); } return false; } function GoBack(anchor) { if (!window.AllowBackFromHistory) { return true; } history.back(); if (!anchor || !anchor.getAttribute) { return true; } var destination = anchor.getAttribute("href"); if (!destination) { return true; } setTimeout(function () { location.href = destination; }, 100); return false; } ================================================ FILE: Telegram/Resources/icons/calls/hands.lottie ================================================ {"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":540,"w":60,"h":60,"nm":"Raise Hand Test","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256.989,275.127,0],"ix":2},"a":{"a":0,"k":[115,115,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"ip":0,"op":119,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"head","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":11,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":23,"s":[-13]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0]},"t":66,"s":[-13]},{"i":{"x":[0.09],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":75,"s":[7]},{"t":92,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":1,"s":[0,-37.327,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":11,"s":[0,-26.827,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":23,"s":[-4.4,-39.427,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":36,"s":[-2.401,-30.424,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":50,"s":[-4.4,-39.427,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.09,"y":1},"o":{"x":0.167,"y":0},"t":66,"s":[-2.401,-30.424,0],"to":[0,0,0],"ti":[0,0,0]},{"t":92,"s":[0,-37.327,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":1,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":5,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":11,"s":[105,95,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":16,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":23,"s":[105,95,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":28,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":36,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":44,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":50,"s":[105,95,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":58,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":66,"s":[100,100,100]},{"i":{"x":[0.09,0.09,0.09],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":75,"s":[95,105,100]},{"t":92,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.341,0],[0,-6.341],[6.341,0],[0,6.341]],"o":[[6.341,0],[0,6.341],[-6.341,0],[0,-6.341]],"v":[[0,-11.482],[11.482,0],[0,11.482],[-11.482,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Oval","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"hands","parent":6,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":21,"s":[-10]},{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":65,"s":[-10]},{"t":93,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[-2.341,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[-2.341,-9.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":21,"s":[-3.741,-17.977,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":35,"s":[-1.541,-11.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":49,"s":[-1.541,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.17,"y":1},"o":{"x":0.6,"y":0},"t":65,"s":[-1.541,-11.777,0],"to":[0,0,0],"ti":[0,0,0]},{"t":93,"s":[-2.341,-17.777,0]}],"ix":2},"a":{"a":0,"k":[115,115,0],"ix":1},"s":{"a":0,"k":[20,20,100],"ix":6}},"ao":0,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"hands 3","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,115,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[0,0],[-4.026,-6.73],[-10.797,-1.273],[-2.119,-0.01]],"o":[[0.65,4.552],[3.882,6.488],[3.499,0.413],[1.186,0.005]],"v":[[-34.027,-30.664],[-27.902,-11.553],[-6.28,2.761],[4.392,3.022]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[0,0],[-0.71,-5.814],[-13.22,1.67],[-6.659,-0.445]],"o":[[-3.232,5.731],[0.566,4.637],[3.994,-0.505],[1.183,0.079]],"v":[[-18.219,-21.464],[-27.079,-2.224],[-7.644,3.484],[11.49,2.929]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[-1.902,-5.873],[-9.833,-0.14],[-7.372,0.373]],"o":[[-4.328,1.758],[1.817,5.11],[4.766,0.217],[1.182,0.009]],"v":[[-17.041,-20.099],[-26.446,-5.406],[-7.078,3.541],[9.615,2.763]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":23,"s":[{"i":[[0,0],[-4.205,-5.986],[-9.957,-1.926],[-4.458,0.474]],"o":[[5.753,4.944],[4.232,6.025],[3.773,0.73],[1.179,-0.125]],"v":[[-37.604,-27.175],[-25.224,-11.553],[-5.844,2.761],[7.055,3.069]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[{"i":[[0,0],[-1.728,-7.979],[-9.811,-4.073],[-4.458,0.474]],"o":[[3.018,5.449],[1.024,4.728],[4.574,1.385],[1.179,-0.125]],"v":[[-30.389,-31.532],[-24.556,-12.392],[-6.174,2.474],[7.055,3.069]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":32,"s":[{"i":[[0,0],[-0.133,-5.267],[-9.077,-3.752],[-4.458,0.474]],"o":[[-4.804,4.722],[0.193,7.66],[5.825,2.408],[1.179,-0.125]],"v":[[-10.804,-33.837],[-18.834,-15.906],[-6.69,2.025],[7.055,3.069]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":37,"s":[{"i":[[0,0],[-0.271,-4.621],[-9.517,-2.839],[-4.458,0.474]],"o":[[-3.394,4.297],[0.242,4.13],[4.799,1.569],[1.179,-0.125]],"v":[[-15.907,-30.468],[-22.029,-13.729],[-6.267,2.393],[7.055,3.069]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":42,"s":[{"i":[[0,0],[-3.928,-6.171],[-9.883,-2.273],[-3.875,0.81]],"o":[[5.522,5.2],[3.954,6.211],[4.837,1.112],[1.161,-0.243]],"v":[[-36.207,-29.267],[-24.551,-13.099],[-5.745,2.464],[7.055,3.069]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[-1.728,-7.979],[-9.811,-4.073],[-4.458,0.474]],"o":[[3.018,5.449],[1.024,4.728],[4.574,1.385],[1.179,-0.125]],"v":[[-30.389,-31.532],[-24.556,-12.392],[-6.174,2.474],[7.055,3.069]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":54,"s":[{"i":[[0,0],[-0.133,-5.267],[-9.319,-3.103],[-4.568,0.674]],"o":[[-4.804,4.722],[0.193,7.66],[5.735,1.909],[1.173,-0.173]],"v":[[-10.804,-33.837],[-18.834,-15.906],[-6.656,1.832],[7.072,2.972]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":61,"s":[{"i":[[0,0],[-0.271,-4.621],[-9.517,-2.839],[-4.458,0.474]],"o":[[-3.394,4.297],[0.242,4.13],[4.799,1.569],[1.179,-0.125]],"v":[[-15.907,-30.468],[-22.029,-13.729],[-6.267,2.393],[7.055,3.069]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":68,"s":[{"i":[[0,0],[-4.205,-5.986],[-9.957,-1.926],[-4.458,0.474]],"o":[[5.753,4.944],[4.232,6.025],[3.773,0.73],[1.179,-0.125]],"v":[[-37.604,-27.175],[-25.224,-11.553],[-5.844,2.761],[7.055,3.069]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":78,"s":[{"i":[[0,0],[-3.924,-6.477],[-10.111,-0.781],[-3.392,0.105]],"o":[[4.365,3.67],[3.808,6.286],[4.491,0.347],[1.183,-0.028]],"v":[[-37.672,-26.337],[-25.271,-10.97],[-5.844,2.761],[6.463,3.033]],"c":false}]},{"t":95,"s":[{"i":[[0,0],[-4.026,-6.73],[-10.797,-1.273],[-2.119,-0.01]],"o":[[0.65,4.552],[3.882,6.488],[3.499,0.413],[1.186,0.005]],"v":[[-34.027,-30.664],[-27.902,-11.553],[-6.28,2.761],[4.392,3.022]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.8,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-8","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"hands 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,115,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[-3.103,0.058],[-2.523,0.098],[-2.257,-5.922],[-0.05,-3.076]],"o":[[2.726,-0.051],[10.848,-0.42],[1.636,4.291],[0,0]],"v":[[3.047,3.014],[11.974,3.008],[30.43,17.71],[32.973,31.114]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[-2.831,0.099],[-2.303,-0.066],[-1.926,-3.085],[-0.239,-5.607]],"o":[[3.206,-0.113],[11.894,0.339],[2.109,3.377],[0,0]],"v":[[2.767,2.88],[11.324,2.869],[28.065,7.836],[30.818,22.809]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":22,"s":[{"i":[[-2.833,0.019],[-2.144,-0.845],[-1.574,-3.736],[-3.615,-5.451]],"o":[[4.963,-0.034],[5.323,2.097],[1.94,4.605],[0,0]],"v":[[2.632,3.384],[12.827,2.873],[22.174,19.291],[30.152,32.241]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":36,"s":[{"i":[[-2.83,-0.135],[-3.536,-1.048],[-1.592,-3.476],[-1.09,-6.235]],"o":[[7.035,0.337],[5.485,1.626],[1.67,3.647],[0,0]],"v":[[1.498,3.488],[12.683,2.542],[23.022,15.874],[26.398,31.323]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":50,"s":[{"i":[[-2.829,0.15],[-2.144,-0.845],[-1.574,-3.736],[-3.615,-5.451]],"o":[[4.712,-0.25],[5.323,2.097],[1.94,4.605],[0,0]],"v":[[2.417,3.447],[12.827,2.873],[22.174,19.291],[30.152,32.241]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":66,"s":[{"i":[[-2.833,0.023],[-3.532,-0.206],[-2.149,-3.438],[-1.064,-6.535]],"o":[[4.317,-0.036],[4.623,0.27],[2.442,3.906],[0,0]],"v":[[1.983,3.325],[12.861,3.014],[29.432,13.325],[34.61,28.122]],"c":false}]},{"t":90,"s":[{"i":[[-3.103,0.058],[-2.523,0.098],[-2.257,-5.922],[-0.05,-3.076]],"o":[[2.726,-0.051],[10.848,-0.42],[1.636,4.291],[0,0]],"v":[[3.047,3.014],[11.974,3.008],[30.43,17.71],[32.973,31.114]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.8,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-8","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"body","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[116.171,151.524,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":21,"s":[116.171,140.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":35,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":49,"s":[116.171,143.924,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.17,"y":0.17},"o":{"x":0.6,"y":0.6},"t":65,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"t":93,"s":[116.171,146.724,0]}],"ix":2},"a":{"a":0,"k":[0,14.211,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":5,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.484,0.484,0.484],"y":[0,0,0]},"t":10,"s":[100,100,100]},{"i":{"x":[0.486,0.486,0.486],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":15,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":21,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":27,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":35,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":42,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":49,"s":[100,100,100]},{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":56,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":65,"s":[100,100,100]},{"i":{"x":[0.17,0.17,0.17],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":77,"s":[97,103,100]},{"t":93,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[0,0],[-0.741,-5.903],[-1.922,-0.751],[-2.946,0],[-2.468,1.063],[-0.228,3.004],[0,0],[0,0]],"o":[[0,0],[0.328,2.608],[2.556,0.999],[2.898,0],[1.959,-0.844],[0.638,-8.388],[0,0],[0,0]],"v":[[-12.432,-14.575],[-11.977,8.464],[-8.487,13.499],[0.4,14.598],[9.223,13.566],[12.656,8.149],[12.482,-13.225],[-1.232,-13.968]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[{"i":[[0,0],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[0,0],[7.2,-1.2]],"o":[[0,0],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,0],[-7.2,1.2]],"v":[[-14.032,-4.05],[-13.127,7.863],[-9.825,12.562],[0.35,14.211],[10.398,12.616],[13.744,7.749],[14.232,-7.571],[-0.968,-7.539]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.5,"y":0},"t":21,"s":[{"i":[[-0.869,-2.458],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[1.3,6.472],[11.956,-3.973]],"o":[[1.863,5.271],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[-0.119,-0.593],[-5.848,1.943]],"v":[[-14.632,-13.411],[-12.127,7.863],[-8.825,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[11.232,-16.011],[-3.825,-14.466]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":35,"s":[{"i":[[-0.896,-2.536],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[2.094,6.249],[8.562,0.638]],"o":[[1.922,5.439],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,-0.172],[-6.543,-0.487]],"v":[[-15.346,-10.627],[-12.527,7.863],[-9.225,12.562],[0.35,14.211],[9.798,12.616],[13.144,7.749],[11.974,-10.116],[-6.43,-8.177]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[-0.878,-2.484],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[1.559,6.399],[11.133,-0.108]],"o":[[1.882,5.326],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[-0.105,-0.49],[-6.188,0.06]],"v":[[-14.481,-12.569],[-12.098,7.863],[-8.796,12.562],[0.35,14.211],[9.369,12.616],[12.715,7.749],[11.484,-13.946],[-3.724,-11.3]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":49,"s":[{"i":[[-0.869,-2.458],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[1.3,6.472],[11.176,-3.111]],"o":[[1.863,5.271],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[-0.119,-0.593],[-6.043,1.682]],"v":[[-14.732,-16.111],[-12.127,7.863],[-8.825,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[11.532,-15.511],[-3.745,-13.528]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":54,"s":[{"i":[[-0.873,-2.469],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[1.413,6.44],[7.166,0.651]],"o":[[1.872,5.295],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[-0.102,-0.533],[-6.261,-0.569]],"v":[[-14.525,-15.487],[-12.348,7.863],[-9.046,12.562],[0.35,14.211],[9.619,12.616],[12.964,7.749],[11.758,-14.741],[-3.318,-12.791]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":57,"s":[{"i":[[-0.878,-2.484],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[1.559,6.399],[7.228,0.668]],"o":[[1.882,5.326],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,0.146],[-6.315,-0.584]],"v":[[-14.816,-12.663],[-12.153,7.863],[-8.85,12.562],[0.35,14.211],[9.424,12.616],[12.769,7.749],[11.588,-12.58],[-3.901,-10.75]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":65,"s":[{"i":[[-0.896,-2.536],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[2.094,6.249],[11.969,-4.333]],"o":[[1.922,5.439],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,-0.172],[-6.23,2.255]],"v":[[-15.524,-9.227],[-12.727,7.863],[-9.425,12.562],[0.35,14.211],[9.998,12.616],[13.344,7.749],[12.174,-10.116],[-3.838,-7.806]],"c":false}]},{"i":{"x":0.17,"y":1},"o":{"x":0.167,"y":0.167},"t":73,"s":[{"i":[[-0.39,-1.104],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[0.912,2.72],[13.551,-2.732]],"o":[[0.837,2.368],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,-0.075],[-6.34,1.278]],"v":[[-14.493,-10.166],[-12.749,7.863],[-9.446,12.562],[0.35,14.211],[10.02,12.616],[13.365,7.749],[12.988,-9.89],[-1.256,-9.949]],"c":false}]},{"t":93,"s":[{"i":[[0,0],[-0.741,-5.903],[-1.922,-0.751],[-2.946,0],[-2.468,1.063],[-0.228,3.004],[0,0],[0,0]],"o":[[0,0],[0.328,2.608],[2.556,0.999],[2.898,0],[1.959,-0.844],[0.638,-8.388],[0,0],[0,0]],"v":[[-12.432,-14.575],[-11.977,8.464],[-8.487,13.499],[0.4,14.598],[9.223,13.566],[12.656,8.149],[12.482,-13.225],[-1.232,-13.968]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256.989,275.127,0],"ix":2},"a":{"a":0,"k":[115,115,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"ip":0,"op":183,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"head","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[0,-37.327,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":11,"s":[0,-27.027,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":23,"s":[0.383,-39.627,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":35,"s":[0.383,-33.606,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":49,"s":[0.383,-39.627,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":63,"s":[0.383,-33.606,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":79,"s":[3.183,-39.627,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.15,"y":1},"o":{"x":0.167,"y":0},"t":93,"s":[3.583,-33.606,0],"to":[0,0,0],"ti":[0,0,0]},{"t":124,"s":[0,-37.327,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":5,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":11,"s":[105,95,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":16,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":23,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":29,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":35,"s":[105,95,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":41,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":49,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":55,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":63,"s":[105,95,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":70,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":79,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":85,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":93,"s":[105,95,100]},{"i":{"x":[0.15,0.15,0.15],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":105,"s":[97,103,100]},{"t":124,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.341,0],[0,-6.341],[6.341,0],[0,6.341]],"o":[[6.341,0],[0,6.341],[-6.341,0],[0,-6.341]],"v":[[0,-11.482],[11.482,0],[0,11.482],[-11.482,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Oval","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":184,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"hands","parent":6,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.16],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":21,"s":[0]},{"t":118,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[-2.341,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[-2.341,-9.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":21,"s":[-1.541,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":33,"s":[-1.541,-15.377,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":47,"s":[-1.541,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":61,"s":[-1.541,-15.377,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":78,"s":[-1.541,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.16,"y":1},"o":{"x":0.5,"y":0},"t":102,"s":[-1.541,-15.377,0],"to":[0,0,0],"ti":[0,0,0]},{"t":118,"s":[-2.341,-17.777,0]}],"ix":2},"a":{"a":0,"k":[115,115,0],"ix":1},"s":{"a":0,"k":[20,20,100],"ix":6}},"ao":0,"ip":0,"op":184,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"hands 3","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,115,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[0,0],[-4.026,-6.73],[-10.797,-1.273],[-2.119,-0.01]],"o":[[0.65,4.552],[3.882,6.488],[3.499,0.413],[1.186,0.005]],"v":[[-34.027,-30.664],[-27.902,-11.553],[-6.28,2.761],[4.392,3.022]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[0,0],[-0.71,-5.814],[-13.22,1.67],[-6.667,-0.441]],"o":[[-3.232,5.731],[0.566,4.637],[3.994,-0.505],[1.183,0.078]],"v":[[-18.219,-21.464],[-27.079,-2.224],[-7.644,3.584],[11.49,2.929]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":23,"s":[{"i":[[0,0],[-1.268,-5.758],[-4.491,-2.782],[-9.089,1.417]],"o":[[-0.238,6.778],[1.347,6.12],[4.565,2.828],[1.172,-0.183]],"v":[[-19.257,-37.475],[-19.531,-14.871],[-9.165,2.078],[11.49,3.527]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":35,"s":[{"i":[[0,0],[-0.961,-3.853],[-6.666,-1.601],[-9.089,1.417]],"o":[[0.03,7.313],[1.517,6.08],[5.221,1.254],[1.172,-0.183]],"v":[[-23.457,-27.675],[-24.527,-6.059],[-7.961,2.838],[11.49,2.929]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":49,"s":[{"i":[[0,0],[-1.268,-5.758],[-4.491,-2.782],[-9.089,1.417]],"o":[[-0.238,6.778],[1.347,6.12],[4.565,2.828],[1.172,-0.183]],"v":[[-19.257,-37.475],[-19.531,-14.871],[-9.165,2.078],[11.49,3.527]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":59,"s":[{"i":[[0,0],[-0.961,-3.853],[-6.666,-1.601],[-9.116,1.293]],"o":[[0.03,7.313],[1.517,6.08],[5.221,1.254],[1.174,-0.167]],"v":[[-23.457,-27.675],[-24.527,-6.059],[-7.961,2.838],[11.49,2.929]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":65,"s":[{"i":[[0,0],[-0.651,-3.886],[-6.545,-1.827],[-9.086,1.105]],"o":[[4.595,6.728],[1.028,6.132],[5.027,1.403],[1.177,-0.143]],"v":[[-25.036,-29.511],[-22.232,-9.273],[-7.789,2.781],[11.545,2.978]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":73,"s":[{"i":[[0,0],[0.125,-3.969],[-6.039,-3.086],[-8.715,1.918]],"o":[[-2.798,7.352],[-0.197,6.263],[4.981,2.545],[1.158,-0.255]],"v":[[-9.536,-38.346],[-16.487,-17.314],[-7.359,2.636],[11.683,3.1]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[-0.447,-3.908],[-4.757,-3.608],[-9.817,2.3]],"o":[[-4.119,5.691],[0.705,6.167],[4.297,3.185],[1.155,-0.271]],"v":[[-10.167,-36.731],[-16.027,-16.023],[-7.359,2.636],[12.29,3.029]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":85,"s":[{"i":[[0,0],[-0.961,-3.853],[-4.491,-2.782],[-7.117,1.703]],"o":[[1.597,6.857],[1.517,6.08],[4.565,2.828],[1.153,-0.276]],"v":[[-20.247,-37.336],[-17.926,-14.859],[-7.359,2.636],[11.59,3.229]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[-0.511,-3.901],[-4.724,-3.504],[-8.017,1.106]],"o":[[2.238,7.884],[0.807,6.156],[4.331,3.14],[1.175,-0.162]],"v":[[-18.139,-37.479],[-16.265,-15.877],[-7.667,2.047],[11.49,2.929]],"c":false}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":96,"s":[{"i":[[0,0],[0.125,-3.969],[-6.039,-3.086],[-9.123,0.867]],"o":[[-2.798,7.352],[-0.197,6.263],[4.981,2.545],[1.181,-0.112]],"v":[[-9.536,-38.346],[-16.487,-17.314],[-7.559,2.136],[11.683,3.1]],"c":false}]},{"t":137,"s":[{"i":[[0,0],[-4.026,-6.73],[-10.797,-1.273],[-2.119,-0.01]],"o":[[0.65,4.552],[3.882,6.488],[3.499,0.413],[1.186,0.005]],"v":[[-34.027,-30.664],[-27.902,-11.553],[-6.28,2.761],[4.392,3.022]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.8,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-8","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":184,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"hands 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,115,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[-3.103,0.058],[-2.523,0.098],[-2.257,-5.922],[-0.05,-3.076]],"o":[[2.726,-0.051],[10.848,-0.42],[1.636,4.291],[0,0]],"v":[[3.047,3.014],[11.974,3.008],[30.43,17.71],[32.973,31.114]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[-2.832,-0.073],[-2.303,-0.066],[-1.926,-3.085],[-0.239,-5.607]],"o":[[2.794,0.072],[11.894,0.339],[2.109,3.377],[0,0]],"v":[[2.763,2.93],[11.216,2.961],[28.065,7.836],[30.818,22.809]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":23,"s":[{"i":[[-2.832,0.111],[-2.264,0.431],[-1.371,7.044],[-0.143,3.51]],"o":[[2.794,-0.11],[8.983,-1.711],[1.168,-6],[0,0]],"v":[[2.891,4.486],[10.849,3.71],[25.852,-14.597],[24.804,-37.956]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":35,"s":[{"i":[[-2.832,0.111],[-2.272,0.384],[-1.192,6.245],[-0.009,3.513]],"o":[[2.794,-0.11],[9.419,-1.594],[1.146,-6.005],[0,0]],"v":[[3.091,3.837],[10.849,3.012],[29.365,-6.408],[27.224,-29.702]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":49,"s":[{"i":[[-2.832,0.111],[-2.264,0.431],[-1.371,7.044],[-0.143,3.51]],"o":[[2.794,-0.11],[8.983,-1.711],[1.168,-6],[0,0]],"v":[[2.891,4.486],[10.849,3.71],[25.852,-14.597],[24.804,-37.956]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":63,"s":[{"i":[[-2.832,0.111],[-2.272,0.384],[-1.192,6.245],[-0.009,3.513]],"o":[[2.794,-0.11],[9.419,-1.594],[1.146,-6.005],[0,0]],"v":[[3.115,3.787],[10.849,3.012],[29.365,-6.408],[27.224,-29.702]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":68,"s":[{"i":[[-2.832,0.111],[-2.329,0.428],[-1.207,6.31],[-0.019,3.512]],"o":[[2.794,-0.11],[9.405,-1.697],[1.148,-6.004],[0,0]],"v":[[3.081,4.077],[10.905,3.036],[29.081,-7.069],[27.028,-30.369]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":81,"s":[{"i":[[-2.832,0.111],[-2.976,0.923],[-1.371,7.044],[-0.143,3.51]],"o":[[2.794,-0.11],[9.238,-2.866],[1.168,-6],[0,0]],"v":[[2.091,4.836],[11.549,3.31],[25.852,-14.597],[24.804,-37.956]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":95,"s":[{"i":[[-2.832,0.111],[-2.272,0.384],[-1.192,6.245],[-0.009,3.513]],"o":[[2.794,-0.11],[9.419,-1.594],[1.146,-6.005],[0,0]],"v":[[3.091,3.837],[10.849,3.012],[29.365,-6.408],[27.224,-29.702]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104,"s":[{"i":[[-2.831,0.08],[-2.289,0.181],[-7.091,2.705],[-0.08,0.435]],"o":[[2.753,-0.078],[9.55,-0.749],[7.091,-2.705],[0,0]],"v":[[2.94,3.427],[10.784,3.015],[28.399,6.452],[28.599,-12.123]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":108,"s":[{"i":[[-2.826,0.181],[-2.296,0.098],[-2.884,-0.516],[0.064,0.955]],"o":[[2.87,-0.184],[9.603,-0.406],[2.056,-0.027],[0,0]],"v":[[2.852,3.381],[10.755,2.875],[28.007,11.666],[29.663,9.28]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[-2.829,0.086],[-2.298,0.077],[-0.947,-0.492],[-0.646,-0.097]],"o":[[2.923,-0.087],[9.617,-0.321],[0.947,0.492],[0,0]],"v":[[2.841,3.319],[10.792,2.896],[27.909,12.969],[29.9,13.784]],"c":false}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[-2.832,-0.009],[-2.3,0.057],[-0.78,-1.215],[-0.945,-1.801]],"o":[[2.976,0.009],[9.63,-0.235],[0.78,1.215],[0,0]],"v":[[2.83,3.257],[10.73,2.954],[27.812,14.272],[30.136,18.289]],"c":false}]},{"t":134,"s":[{"i":[[-3.103,0.058],[-2.523,0.098],[-2.257,-5.922],[-0.05,-3.076]],"o":[[2.726,-0.051],[10.848,-0.42],[1.636,4.291],[0,0]],"v":[[3.047,3.014],[11.974,3.008],[30.43,17.71],[32.973,31.114]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.8,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-8","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":184,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"body","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.31,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[116.171,151.524,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.31,"y":1},"o":{"x":0.69,"y":0},"t":21,"s":[116.171,140.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.31,"y":1},"o":{"x":0.69,"y":0},"t":33,"s":[116.171,150.324,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.31,"y":1},"o":{"x":0.69,"y":0},"t":47,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.31,"y":1},"o":{"x":0.69,"y":0},"t":61,"s":[116.171,150.324,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.31,"y":1},"o":{"x":0.69,"y":0},"t":78,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.69,"y":0},"t":102,"s":[116.171,150.324,0],"to":[0,0,0],"ti":[0,0,0]},{"t":133,"s":[116.171,146.724,0]}],"ix":2},"a":{"a":0,"k":[0,14.211,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":5,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.484,0.484,0.484],"y":[0,0,0]},"t":10,"s":[100,100,100]},{"i":{"x":[0.31,0.31,0.31],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":15,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.563,0.563,0.563],"y":[0,0,0]},"t":21,"s":[100,100,100]},{"i":{"x":[0.219,0.219,0.219],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":27,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.406,0.406,0.406],"y":[0,0,0]},"t":33,"s":[100,100,100]},{"i":{"x":[0.233,0.233,0.233],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":40,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.69,0.69,0.69],"y":[0,0,0]},"t":47,"s":[100,100,100]},{"i":{"x":[0.31,0.31,0.31],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":54,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.495,0.495,0.495],"y":[0,0,0]},"t":61,"s":[100,100,100]},{"i":{"x":[0.203,0.203,0.203],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":67,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.69,0.69,0.69],"y":[0,0,0]},"t":78,"s":[100,100,100]},{"i":{"x":[0.31,0.31,0.31],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":89,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.495,0.495,0.495],"y":[0,0,0]},"t":102,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":117,"s":[103,97,100]},{"t":133,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[0,0],[-0.741,-5.903],[-1.922,-0.751],[-2.946,0],[-2.468,1.063],[-0.228,3.004],[0,0],[0,0]],"o":[[0,0],[0.328,2.608],[2.556,0.999],[2.898,0],[1.959,-0.844],[0.638,-8.388],[0,0],[0,0]],"v":[[-12.432,-14.575],[-11.977,8.464],[-8.487,13.499],[0.4,14.598],[9.223,13.566],[12.656,8.149],[12.482,-13.225],[0.089,-13.897]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[{"i":[[0,0],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[0,0],[0,0]],"o":[[0,0],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,0],[0,0]],"v":[[-13.432,-6.25],[-13.127,7.863],[-9.825,12.562],[0.35,14.211],[10.398,12.616],[13.744,7.749],[13.432,-6.171],[0.069,-6.21]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.5,"y":0},"t":21,"s":[{"i":[[0,0],[0,0],[-1.772,-0.83],[-2.763,0],[-2.314,1.063],[-0.081,2.131],[0,0],[4.6,0.1]],"o":[[0,0],[0.132,2.059],[2.348,1.099],[2.717,0],[1.837,-0.844],[0,0],[0,0],[-4.6,-0.1]],"v":[[-12.732,-16.711],[-11.415,7.863],[-8.318,12.562],[0.348,14.211],[8.894,12.616],[12.032,7.749],[12.732,-14.111],[0.032,-12.939]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0},"t":33,"s":[{"i":[[0,0],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[0,0],[0,0]],"o":[[0,0],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,0],[0,0]],"v":[[-13.832,-12.011],[-12.127,7.863],[-8.825,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[13.832,-12.011],[0.071,-12.011]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.5,"y":0},"t":47,"s":[{"i":[[0,0],[0,0],[-1.772,-0.83],[-2.763,0],[-2.314,1.063],[-0.081,2.131],[0,0],[0,0]],"o":[[0,0],[0.132,2.059],[2.348,1.099],[2.717,0],[1.837,-0.844],[0,0],[0,0],[0,0]],"v":[[-12.732,-16.711],[-11.415,7.863],[-8.318,12.562],[0.348,14.211],[8.894,12.616],[12.032,7.749],[12.732,-14.111],[0.065,-13.504]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,0],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[0,0],[0,0]],"o":[[0,0],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,0],[0,0]],"v":[[-13.832,-12.011],[-12.127,7.863],[-8.825,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[13.832,-12.011],[0.071,-12.011]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":68,"s":[{"i":[[0.583,-2.853],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-1.681,3.721],[9.547,0.72]],"o":[[-1.162,5.686],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.172,-0.387],[-6.293,-0.475]],"v":[[-11.685,-13.446],[-12.103,7.863],[-8.8,12.562],[0.35,14.211],[9.374,12.616],[12.719,7.749],[13.832,-14.267],[-0.931,-12.07]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":78,"s":[{"i":[[0.583,-2.853],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-1.202,3.902],[10.545,0.088]],"o":[[-1.162,5.686],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.108,-0.363],[-6.244,-0.052]],"v":[[-11.402,-16.846],[-12.127,7.863],[-8.825,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[13.815,-16.611],[-0.813,-13.327]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0.279,-1.426],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-0.575,1.951],[6.396,0.322]],"o":[[-0.556,2.843],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.052,-0.181],[-8.294,-0.418]],"v":[[-11.944,-17.745],[-12.154,7.863],[-8.852,12.562],[0.35,14.211],[9.425,12.616],[12.771,7.749],[13.386,-13.461],[-1.432,-12.505]],"c":false}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":102,"s":[{"i":[[0,0],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[0,0],[0,0]],"o":[[0,0],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,0],[0,0]],"v":[[-12.832,-15.411],[-12.127,7.863],[-8.825,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[12.932,-11.911],[-1.184,-11.652]],"c":false}]},{"t":133,"s":[{"i":[[0,0],[-0.741,-5.903],[-1.922,-0.751],[-2.946,0],[-2.468,1.063],[-0.228,3.004],[0,0],[0,0]],"o":[[0,0],[0.328,2.608],[2.556,0.999],[2.898,0],[1.959,-0.844],[0.638,-8.388],[0,0],[0,0]],"v":[[-12.432,-14.575],[-11.977,8.464],[-8.487,13.499],[0.4,14.598],[9.223,13.566],[12.656,8.149],[12.482,-13.225],[0.089,-13.897]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":184,"st":0,"bm":0}]},{"id":"comp_2","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256.989,275.127,0],"ix":2},"a":{"a":0,"k":[115,115,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"ip":0,"op":119,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"head","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":11,"s":[0]},{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":23,"s":[21]},{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":36,"s":[11]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":50,"s":[21]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.243],"y":[0]},"t":68,"s":[21]},{"i":{"x":[0.566],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":78,"s":[-15.198]},{"t":88,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":1,"s":[0,-37.327,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":11,"s":[0,-26.927,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":23,"s":[5.6,-39.527,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":36,"s":[4,-29.127,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0},"t":50,"s":[5.6,-39.527,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.5,"y":0},"t":66,"s":[4,-30.327,0],"to":[0,0,0],"ti":[0,0,0]},{"t":88,"s":[0,-37.327,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":1,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":5,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":11,"s":[105,95,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":16,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":23,"s":[105,95,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":29,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":36,"s":[105,95,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":43,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":50,"s":[105,95,100]},{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":57,"s":[95,105,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":66,"s":[102,98,100]},{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":78,"s":[95,105,100]},{"t":88,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.341,0],[0,-6.341],[6.341,0],[0,6.341]],"o":[[6.341,0],[0,6.341],[-6.341,0],[0,-6.341]],"v":[[0,-11.482],[11.482,0],[0,11.482],[-11.482,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Oval","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"hands","parent":6,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":21,"s":[8]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":49,"s":[8]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[8]},{"t":89,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[-2.341,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[-2.341,-9.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":21,"s":[-1.541,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":35,"s":[-1.541,-11.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":49,"s":[-1.541,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.6,"y":0},"t":65,"s":[-1.541,-11.777,0],"to":[0,0,0],"ti":[0,0,0]},{"t":89,"s":[-2.341,-17.777,0]}],"ix":2},"a":{"a":0,"k":[115,115,0],"ix":1},"s":{"a":0,"k":[20,20,100],"ix":6}},"ao":0,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"hands 3","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,115,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[0,0],[-4.026,-6.73],[-10.797,-1.273],[-2.119,-0.01]],"o":[[0.65,4.552],[3.882,6.488],[3.499,0.413],[1.186,0.005]],"v":[[-34.027,-30.664],[-27.902,-11.553],[-6.28,2.761],[4.392,3.022]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[0,0],[-0.71,-5.814],[-13.22,1.67],[-6.659,-0.445]],"o":[[-3.232,5.731],[0.566,4.637],[3.994,-0.505],[1.183,0.079]],"v":[[-18.219,-21.464],[-27.079,-2.224],[-7.644,3.484],[10.985,2.86]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":23,"s":[{"i":[[0,0],[-0.961,-3.853],[-4.984,-1.753],[-8.926,0.862]],"o":[[1.597,6.857],[1.517,6.08],[5.484,1.929],[1.18,-0.114]],"v":[[-20.247,-37.336],[-17.926,-14.859],[-7.906,2.713],[8.267,2.627]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":37,"s":[{"i":[[0,0],[-1.803,-4.807],[-6.68,-0.3],[-7.645,-0.484]],"o":[[-1.052,7.028],[2.083,5.552],[5.685,0.256],[1.184,0.075]],"v":[[-20.218,-23.988],[-22.536,-2.921],[-7.359,2.636],[10.433,2.572]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.7,"y":0},"t":51,"s":[{"i":[[0,0],[-0.961,-3.853],[-4.984,-1.753],[-8.926,0.862]],"o":[[1.597,6.857],[1.517,6.08],[5.484,1.929],[1.18,-0.114]],"v":[[-20.247,-37.336],[-17.926,-14.859],[-7.906,2.713],[8.267,2.627]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.4,"y":0},"t":67,"s":[{"i":[[0,0],[-1.803,-4.807],[-6.68,-0.3],[-7.645,-0.484]],"o":[[-1.052,7.028],[2.083,5.552],[5.685,0.256],[1.184,0.075]],"v":[[-20.218,-23.988],[-22.536,-2.921],[-7.359,2.636],[10.433,2.572]],"c":false}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0.167},"t":78,"s":[{"i":[[0,0],[-1.746,-7.006],[-9.167,-1.369],[-3.018,-0.266]],"o":[[-3.628,5.112],[1.694,6.8],[4.106,0.209],[1.182,0.076]],"v":[[-20.614,-25.461],[-25.11,-7.259],[-6.208,2.731],[7.297,3.206]],"c":false}]},{"t":105,"s":[{"i":[[0,0],[-4.026,-6.73],[-10.797,-1.273],[-2.119,-0.01]],"o":[[0.65,4.552],[3.882,6.488],[3.499,0.413],[1.186,0.005]],"v":[[-34.027,-30.664],[-27.902,-11.553],[-6.28,2.761],[4.392,3.022]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.8,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-8","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"hands 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,115,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[-3.103,0.058],[-2.523,0.098],[-2.257,-5.922],[-0.05,-3.076]],"o":[[2.726,-0.051],[10.848,-0.42],[1.636,4.291],[0,0]],"v":[[3.047,3.014],[11.974,3.008],[30.43,17.71],[32.973,31.114]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[-2.832,-0.073],[-2.303,-0.066],[-1.926,-3.085],[-0.239,-5.607]],"o":[[2.794,0.072],[11.894,0.339],[2.109,3.377],[0,0]],"v":[[2.747,2.681],[11.207,2.811],[28.065,7.836],[30.818,22.809]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":22,"s":[{"i":[[-2.805,0.395],[-2.144,-0.845],[-1.574,-3.736],[-3.615,-5.451]],"o":[[4.23,-0.595],[5.323,2.097],[1.94,4.605],[0,0]],"v":[[2.696,3.339],[12.911,2.962],[22.174,19.291],[30.152,32.241]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":36,"s":[{"i":[[-2.83,0.127],[-2.144,-0.845],[-1.985,-3.535],[-1.3,-6.195]],"o":[[5.352,-0.241],[5.323,2.097],[1.964,3.497],[0,0]],"v":[[1.908,2.538],[13.562,3.072],[22.983,13.903],[27.16,28.662]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.6,"y":0},"t":50,"s":[{"i":[[-2.805,0.395],[-2.144,-0.845],[-1.574,-3.736],[-3.615,-5.451]],"o":[[4.23,-0.595],[5.323,2.097],[1.94,4.605],[0,0]],"v":[[2.696,3.339],[12.911,2.962],[22.174,19.291],[30.152,32.241]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":58,"s":[{"i":[[-2.818,0.261],[-2.144,-0.845],[-1.78,-3.636],[-2.457,-5.823]],"o":[[4.791,-0.418],[5.323,2.097],[1.952,4.051],[0,0]],"v":[[2.321,3.134],[13.236,3.017],[22.578,16.597],[28.656,30.451]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.4,"y":0},"t":66,"s":[{"i":[[-2.83,0.127],[-2.144,-0.845],[-1.985,-3.535],[-1.3,-6.195]],"o":[[5.352,-0.241],[5.323,2.097],[1.964,3.497],[0,0]],"v":[[1.908,2.538],[13.562,3.072],[22.983,13.903],[27.16,28.662]],"c":false}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0.167},"t":76,"s":[{"i":[[-2.803,-0.138],[-2.518,-0.399],[-2.207,-4.957],[2.376,-4.348]],"o":[[3.802,0.187],[4.102,0.65],[1.627,3.656],[0,0]],"v":[[1.941,2.94],[11.88,3.616],[26.524,13.453],[23.943,27.653]],"c":false}]},{"t":97,"s":[{"i":[[-3.103,0.058],[-2.523,0.098],[-2.257,-5.922],[-0.05,-3.076]],"o":[[2.726,-0.051],[10.848,-0.42],[1.636,4.291],[0,0]],"v":[[3.047,3.014],[11.974,3.008],[30.43,17.71],[32.973,31.114]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.8,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-8","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"body","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[116.171,151.524,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":21,"s":[116.171,140.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":35,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":49,"s":[116.171,143.924,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.6,"y":0.6},"t":65,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"t":89,"s":[116.171,146.724,0]}],"ix":2},"a":{"a":0,"k":[0,14.211,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":5,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.484,0.484,0.484],"y":[0,0,0]},"t":10,"s":[100,100,100]},{"i":{"x":[0.486,0.486,0.486],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":15,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":21,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":27,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":35,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":42,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":49,"s":[100,100,100]},{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":56,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":65,"s":[100,100,100]},{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":76,"s":[97,103,100]},{"t":89,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[0,0],[-0.741,-5.903],[-1.922,-0.751],[-2.946,0],[-2.468,1.063],[-0.228,3.004],[0,0],[0,0]],"o":[[0,0],[0.328,2.608],[2.556,0.999],[2.898,0],[1.959,-0.844],[0.638,-8.388],[0,0],[0,0]],"v":[[-12.432,-14.575],[-11.977,8.464],[-8.487,13.499],[0.4,14.598],[9.223,13.566],[12.656,8.149],[12.482,-13.225],[-2.127,-14.017]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[{"i":[[0,0],[0,0],[-2.036,-0.83],[-3.175,0],[-2.659,1.063],[-0.093,2.131],[0,0],[0,0]],"o":[[0,0],[0.446,2.497],[2.698,1.099],[3.123,0],[2.111,-0.844],[0,0],[0,0],[0,0]],"v":[[-14.932,-5.55],[-13.915,7.864],[-10.056,12.562],[0.354,14.211],[10.626,12.616],[14.232,7.749],[14.732,-4.571],[-1.668,-6.839]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":21,"s":[{"i":[[0.416,-4.877],[0,0],[-1.748,-0.83],[-2.726,0],[-2.283,1.063],[-0.08,2.131],[-1.162,6.43],[7.773,-0.606]],"o":[[-0.818,9.587],[0.13,2.059],[2.317,1.099],[2.681,0],[1.812,-0.844],[0,0],[0.023,-0.095],[-6.044,0.472]],"v":[[-11.695,-16.726],[-11.827,7.863],[-8.772,12.562],[0.392,14.211],[9.438,12.616],[12.534,7.749],[14.054,-9.469],[3.058,-14.133]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":35,"s":[{"i":[[0.168,-4.901],[0,0],[-1.759,-0.83],[-2.743,0],[-2.297,1.063],[-0.08,2.131],[-1.325,4.892],[7.682,-1.08]],"o":[[-0.283,8.264],[0.131,2.059],[2.331,1.099],[2.698,0],[1.823,-0.844],[0,0],[0.15,-0.385],[-6.216,0.874]],"v":[[-12.874,-10.003],[-11.908,7.863],[-8.834,12.562],[0.377,14.211],[9.469,12.616],[12.584,7.749],[14.152,-3.848],[-1.25,-8.759]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":49,"s":[{"i":[[0.416,-4.877],[0,0],[-1.748,-0.83],[-2.726,0],[-2.283,1.063],[-0.08,2.131],[-1.162,6.43],[9.673,-2.072]],"o":[[-0.818,9.587],[0.13,2.059],[2.317,1.099],[2.681,0],[1.812,-0.844],[0,0],[0.023,-0.095],[-5.963,1.277]],"v":[[-11.695,-17.126],[-11.827,7.863],[-8.772,12.562],[0.392,14.211],[9.438,12.616],[12.534,7.749],[14.054,-9.469],[-0.642,-13.867]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.6,"y":0},"t":65,"s":[{"i":[[0.168,-4.901],[0,0],[-1.759,-0.83],[-2.743,0],[-2.297,1.063],[-0.08,2.131],[-1.325,4.892],[9.682,-1.898]],"o":[[-0.283,8.264],[0.131,2.059],[2.331,1.099],[2.698,0],[1.823,-0.844],[0,0],[0.15,-0.385],[-6.146,1.205]],"v":[[-12.874,-10.003],[-11.908,7.863],[-8.834,12.562],[0.377,14.211],[9.469,12.616],[12.584,7.749],[14.152,-4.048],[-1.55,-8.541]],"c":false}]},{"t":89,"s":[{"i":[[0,0],[-0.741,-5.903],[-1.922,-0.751],[-2.946,0],[-2.468,1.063],[-0.228,3.004],[0,0],[0,0]],"o":[[0,0],[0.328,2.608],[2.556,0.999],[2.898,0],[1.959,-0.844],[0.638,-8.388],[0,0],[0,0]],"v":[[-12.432,-14.575],[-11.977,8.464],[-8.487,13.499],[0.4,14.598],[9.223,13.566],[12.656,8.149],[12.482,-13.225],[-2.127,-14.017]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}]},{"id":"comp_3","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256.989,275.127,0],"ix":2},"a":{"a":0,"k":[115,115,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"ip":0,"op":119,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"head","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":11,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":23,"s":[21]},{"t":107,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":1,"s":[122.706,17.15,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":11,"s":[122.706,68.999,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.589,"y":1},"o":{"x":0.275,"y":0},"t":23,"s":[150.706,5.999,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.206,"y":0},"t":32,"s":[150.706,32.05,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.589,"y":1},"o":{"x":0.275,"y":0},"t":40,"s":[150.706,27.67,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.206,"y":0},"t":47,"s":[150.706,32.05,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.589,"y":1},"o":{"x":0.275,"y":0},"t":54,"s":[150.706,27.67,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.206,"y":0},"t":61,"s":[150.706,32.05,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.6,"y":0},"t":70,"s":[150.706,27.67,0],"to":[0,0,0],"ti":[0,0,0]},{"t":107,"s":[122.706,17.15,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":1,"s":[500,500,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":5,"s":[485,515,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":11,"s":[525,475,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":16,"s":[485,515,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":23,"s":[525,475,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":32,"s":[500,500,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":40,"s":[500,500,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":47,"s":[500,500,100]},{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":54,"s":[500,500,100]},{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":61,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":70,"s":[500,500,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":77,"s":[480,520,100]},{"t":107,"s":[500,500,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.341,0],[0,-6.341],[6.341,0],[0,6.341]],"o":[[6.341,0],[0,6.341],[-6.341,0],[0,-6.341]],"v":[[0,-11.482],[11.482,0],[0,11.482],[-11.482,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Oval","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"NULL CONTROL","parent":7,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.5,"y":0},"t":21,"s":[-1.541,-17.777,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.13,"y":1},"o":{"x":0.6,"y":0},"t":66,"s":[-1.541,-20.177,0],"to":[0,0,0],"ti":[0,0,0]},{"t":94,"s":[-1.541,-17.777,0]}],"ix":2},"a":{"a":0,"k":[115,115,0],"ix":1},"s":{"a":0,"k":[20,20,100],"ix":6}},"ao":0,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":3,"nm":"hands","parent":3,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":23,"s":[8]},{"i":{"x":[0.13],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[8]},{"t":94,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[111,115,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[111,155,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0},"t":23,"s":[115,115,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0},"t":30,"s":[115,121,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0},"t":38,"s":[115,115,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0},"t":45,"s":[115,121,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0},"t":53,"s":[115,115,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0},"t":57,"s":[115,121,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.13,"y":1},"o":{"x":0.6,"y":0},"t":65,"s":[115,115,0],"to":[0,0,0],"ti":[0,0,0]},{"t":94,"s":[111,115,0]}],"ix":2},"a":{"a":0,"k":[115,115,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"hands 3","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,115,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[0,0],[-4.026,-6.73],[-10.797,-1.273],[-2.119,-0.01]],"o":[[0.65,4.552],[3.882,6.488],[3.499,0.413],[1.186,0.005]],"v":[[-34.027,-30.664],[-27.902,-11.553],[-6.28,2.761],[4.392,3.022]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[0,0],[-0.71,-5.814],[-13.22,1.67],[-6.666,-0.138]],"o":[[-3.232,5.731],[0.566,4.637],[3.994,-0.505],[1.186,0.024]],"v":[[-18.219,-21.464],[-27.079,-2.224],[-7.644,3.484],[11.485,2.829]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":23,"s":[{"i":[[0,0],[-0.961,-3.853],[-4.491,-2.782],[-8.28,0.661]],"o":[[1.597,6.857],[1.517,6.08],[4.565,2.828],[1.182,-0.094]],"v":[[-20.247,-37.336],[-17.926,-14.859],[-7.359,2.636],[10.724,2.534]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":26,"s":[{"i":[[0,0],[-0.511,-3.901],[-4.724,-3.504],[-8.291,0.526]],"o":[[2.238,7.884],[0.807,6.156],[4.331,3.14],[1.184,-0.075]],"v":[[-18.139,-37.479],[-16.265,-15.877],[-7.359,2.636],[10.941,2.657]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":30,"s":[{"i":[[0,0],[0.125,-3.969],[-5.052,-4.524],[-8.435,1.023]],"o":[[-2.798,7.352],[-0.197,6.263],[4,3.582],[1.177,-0.143]],"v":[[-6.969,-38.346],[-13.919,-17.314],[-7.359,2.636],[9.48,3.009]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":34,"s":[{"i":[[0,0],[-0.447,-3.908],[-4.757,-3.608],[-8.213,0.625]],"o":[[-4.119,5.691],[0.705,6.167],[4.297,3.185],[1.182,-0.09]],"v":[[-10.167,-36.731],[-16.027,-16.023],[-7.359,2.636],[11.49,2.929]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":37.666,"s":[{"i":[[0,0],[-0.961,-3.853],[-4.491,-2.782],[-8.28,0.661]],"o":[[1.597,6.857],[1.517,6.08],[4.565,2.828],[1.182,-0.094]],"v":[[-20.247,-37.336],[-17.926,-14.859],[-7.359,2.636],[10.724,2.534]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":41,"s":[{"i":[[0,0],[-0.511,-3.901],[-4.724,-3.504],[-8.291,0.526]],"o":[[2.238,7.884],[0.807,6.156],[4.331,3.14],[1.184,-0.075]],"v":[[-18.139,-37.479],[-16.265,-15.877],[-7.359,2.636],[10.941,2.657]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":45,"s":[{"i":[[0,0],[0.125,-3.969],[-5.052,-4.524],[-8.435,1.023]],"o":[[-2.798,7.352],[-0.197,6.263],[4,3.582],[1.177,-0.143]],"v":[[-6.969,-38.346],[-13.919,-17.314],[-7.359,2.636],[9.48,3.009]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[-0.447,-3.908],[-4.757,-3.608],[-8.213,0.625]],"o":[[-4.119,5.691],[0.705,6.167],[4.297,3.185],[1.182,-0.09]],"v":[[-10.167,-36.731],[-16.027,-16.023],[-7.359,2.636],[11.49,2.929]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":52.334,"s":[{"i":[[0,0],[-0.961,-3.853],[-4.491,-2.782],[-8.28,0.661]],"o":[[1.597,6.857],[1.517,6.08],[4.565,2.828],[1.182,-0.094]],"v":[[-20.247,-37.336],[-17.926,-14.859],[-7.359,2.636],[10.724,2.534]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":56,"s":[{"i":[[0,0],[-0.511,-3.901],[-4.724,-3.504],[-8.291,0.526]],"o":[[2.238,7.884],[0.807,6.156],[4.331,3.14],[1.184,-0.075]],"v":[[-18.139,-37.479],[-16.265,-15.877],[-7.359,2.636],[10.941,2.657]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":60,"s":[{"i":[[0,0],[0.125,-3.969],[-5.052,-4.524],[-8.435,1.023]],"o":[[-2.798,7.352],[-0.197,6.263],[4,3.582],[1.177,-0.143]],"v":[[-6.969,-38.346],[-13.919,-17.314],[-7.359,2.636],[9.48,3.009]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":64,"s":[{"i":[[0,0],[-0.447,-3.908],[-4.757,-3.608],[-8.213,0.625]],"o":[[-4.119,5.691],[0.705,6.167],[4.297,3.185],[1.182,-0.09]],"v":[[-10.167,-36.731],[-16.027,-16.023],[-7.359,2.636],[11.49,2.929]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":68,"s":[{"i":[[0,0],[-0.961,-3.853],[-4.491,-2.782],[-8.28,0.661]],"o":[[1.597,6.857],[1.517,6.08],[4.565,2.828],[1.182,-0.094]],"v":[[-20.247,-37.336],[-17.926,-14.859],[-7.359,2.636],[10.724,2.534]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":71.666,"s":[{"i":[[0,0],[-0.511,-3.901],[-4.724,-3.504],[-8.522,-0.294]],"o":[[2.238,7.884],[0.807,6.156],[4.331,3.14],[1.185,0.041]],"v":[[-18.139,-37.479],[-16.265,-15.877],[-7.359,2.636],[11.49,2.929]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":76,"s":[{"i":[[0,0],[0.125,-3.969],[-5.052,-4.524],[-9.764,-0.338]],"o":[[-2.798,7.352],[-0.197,6.263],[4,3.582],[1.185,0.041]],"v":[[-6.969,-38.346],[-13.919,-17.314],[-7.359,2.636],[11.487,2.829]],"c":false}]},{"i":{"x":0.09,"y":1},"o":{"x":0.167,"y":0.167},"t":84,"s":[{"i":[[0,0],[-1.151,-9.822],[-6.924,-2.401],[-5.542,0.051]],"o":[[-3.654,5.5],[0.733,6.255],[4.389,1.538],[1.186,-0.011]],"v":[[-12.896,-35.078],[-19.976,-13.433],[-7.442,2.05],[9.027,3.064]],"c":false}]},{"t":104,"s":[{"i":[[0,0],[-4.026,-6.73],[-10.797,-1.273],[-2.119,-0.01]],"o":[[0.65,4.552],[3.882,6.488],[3.499,0.413],[1.186,0.005]],"v":[[-34.027,-30.664],[-27.902,-11.553],[-6.28,2.761],[4.392,3.022]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.8,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-8","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"hands 2","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,115,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[500,500,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[-3.103,0.058],[-2.523,0.098],[-2.257,-5.922],[-0.05,-3.076]],"o":[[2.726,-0.051],[10.848,-0.42],[1.636,4.291],[0,0]],"v":[[3.047,3.014],[11.974,3.008],[30.43,17.71],[32.973,31.114]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[-2.832,-0.073],[-2.303,-0.066],[-1.926,-3.085],[-0.239,-5.607]],"o":[[2.794,0.072],[11.894,0.339],[2.109,3.377],[0,0]],"v":[[2.758,2.83],[11.206,2.761],[28.065,7.836],[30.818,22.809]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":23,"s":[{"i":[[-2.816,0.314],[-2.144,-0.845],[-1.574,-3.736],[-3.615,-5.451]],"o":[[4.14,-0.462],[5.323,2.097],[1.94,4.605],[0,0]],"v":[[2.456,3.576],[12.827,2.873],[22.174,19.291],[30.152,32.241]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":31,"s":[{"i":[[-2.805,0.396],[-2.168,-0.779],[-1.2,-3.73],[-2.259,-5.223]],"o":[[3.592,-0.507],[6.085,2.162],[1.511,4.741],[0,0]],"v":[[2.725,4.04],[12.869,3.17],[22.316,18.867],[27.587,32.67]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":38,"s":[{"i":[[-2.816,0.314],[-2.144,-0.845],[-1.574,-3.736],[-3.615,-5.451]],"o":[[4.14,-0.462],[5.323,2.097],[1.94,4.605],[0,0]],"v":[[2.456,3.576],[12.827,2.873],[22.174,19.291],[30.152,32.241]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":46,"s":[{"i":[[-2.805,0.396],[-2.168,-0.779],[-1.2,-3.73],[-2.259,-5.223]],"o":[[3.592,-0.507],[6.085,2.162],[1.511,4.741],[0,0]],"v":[[2.725,4.04],[12.869,3.17],[22.316,18.867],[27.587,32.67]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":53,"s":[{"i":[[-2.816,0.314],[-2.144,-0.845],[-1.574,-3.736],[-3.615,-5.451]],"o":[[4.14,-0.462],[5.323,2.097],[1.94,4.605],[0,0]],"v":[[2.456,3.576],[12.827,2.873],[22.174,19.291],[30.152,32.241]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.5,"y":0},"t":61,"s":[{"i":[[-2.805,0.396],[-2.168,-0.779],[-1.2,-3.73],[-2.259,-5.223]],"o":[[3.592,-0.507],[6.085,2.162],[1.511,4.741],[0,0]],"v":[[2.725,4.04],[12.869,3.17],[22.316,18.867],[27.587,32.67]],"c":false}]},{"i":{"x":0.13,"y":1},"o":{"x":0.6,"y":0},"t":69,"s":[{"i":[[-2.816,0.314],[-2.144,-0.845],[-1.574,-3.736],[-3.615,-5.451]],"o":[[4.14,-0.462],[5.323,2.097],[1.94,4.605],[0,0]],"v":[[2.456,3.576],[12.827,2.873],[22.174,19.291],[30.152,32.241]],"c":false}]},{"t":100,"s":[{"i":[[-3.103,0.058],[-2.523,0.098],[-2.257,-5.922],[-0.05,-3.076]],"o":[[2.726,-0.051],[10.848,-0.42],[1.636,4.291],[0,0]],"v":[[3.047,3.014],[11.974,3.008],[30.43,17.71],[32.973,31.114]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.8,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-8","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"body","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[116.171,151.524,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.723,"y":1},"o":{"x":0.395,"y":0},"t":21,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.361,"y":0},"t":30,"s":[116.171,147.924,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.723,"y":1},"o":{"x":0.395,"y":0},"t":38,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.361,"y":0},"t":45,"s":[116.171,147.924,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.723,"y":1},"o":{"x":0.395,"y":0},"t":52,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.361,"y":0},"t":59,"s":[116.171,147.924,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.104,"y":0.104},"o":{"x":0.395,"y":0.395},"t":66,"s":[116.171,146.724,0],"to":[0,0,0],"ti":[0,0,0]},{"t":94,"s":[116.171,146.724,0]}],"ix":2},"a":{"a":0,"k":[0,14.211,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":5,"s":[97,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.484,0.484,0.484],"y":[0,0,0]},"t":10,"s":[100,100,100]},{"i":{"x":[0.486,0.486,0.486],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":15,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":21,"s":[100,100,100]},{"i":{"x":[0.486,0.486,0.486],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":25,"s":[98,102,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":30,"s":[100,100,100]},{"i":{"x":[0.486,0.486,0.486],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":34,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.48,0.48,0.48],"y":[0,0,0]},"t":38,"s":[100,100,100]},{"i":{"x":[0.471,0.471,0.471],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":41,"s":[98,102,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.537,0.537,0.537],"y":[0,0,0]},"t":45,"s":[100,100,100]},{"i":{"x":[0.582,0.582,0.582],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":49,"s":[103,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.48,0.48,0.48],"y":[0,0,0]},"t":52,"s":[100,100,100]},{"i":{"x":[0.471,0.471,0.471],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":55,"s":[98,102,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.468,0.468,0.468],"y":[0,0,0]},"t":59,"s":[100,100,100]},{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":62,"s":[103,97,100]},{"i":{"x":[0.13,0.13,0.13],"y":[1,1,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":66,"s":[100,100,100]},{"t":94,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[0,0],[-0.741,-5.903],[-1.922,-0.751],[-2.946,0],[-2.468,1.063],[-0.228,3.004],[0,0],[0,0],[0,0]],"o":[[0,0],[0.328,2.608],[2.556,0.999],[2.898,0],[1.959,-0.844],[0.638,-8.388],[0,0],[0,0],[0,0]],"v":[[-12.432,-14.575],[-11.977,8.464],[-8.487,13.499],[0.4,14.598],[9.223,13.566],[12.656,8.149],[12.482,-13.225],[8.179,-13.458],[-3.728,-14.103]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":10,"s":[{"i":[[0,0],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[0,0],[0,0],[0,0]],"o":[[0,0],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0,0],[0,0],[0,0]],"v":[[-14.032,-5.05],[-13.127,7.863],[-9.825,12.562],[0.35,14.211],[10.398,12.616],[13.744,7.749],[14.232,-5.571],[9.351,-5.481],[-4.158,-6.032]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":23,"s":[{"i":[[0.662,-3.59],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-2.532,4.395],[2.35,1.639],[4.409,1.158]],"o":[[-1.585,8.587],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.006,-0.084],[-3.61,-2.518],[-3.578,-0.94]],"v":[[-11.286,-17.808],[-12.133,7.863],[-8.83,12.562],[0.35,14.211],[9.404,12.616],[12.749,7.749],[13.232,-10.927],[9.318,-13.932],[-4.455,-14.008]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[1.056,-3.495],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-3.19,3.944],[2.35,1.814],[4.6,1.543]],"o":[[-2.702,8.946],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.021,-0.037],[-3.61,-2.786],[-3.733,-1.252]],"v":[[-11.366,-17.585],[-11.927,7.863],[-8.625,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[14.152,-8.699],[10.273,-11.929],[-3.437,-12.668]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":38,"s":[{"i":[[0.662,-3.59],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-2.532,4.395],[2.35,1.804],[4.409,1.445]],"o":[[-1.585,8.587],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.006,-0.084],[-3.61,-2.771],[-3.578,-1.173]],"v":[[-11.286,-19.408],[-12.133,7.863],[-8.83,12.562],[0.35,14.211],[9.404,12.616],[12.749,7.749],[13.232,-10.927],[9.318,-14.209],[-5.653,-15.762]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[3.203,-10.603],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-3.19,3.944],[3,-0.7],[3.7,2]],"o":[[-2.702,8.946],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.08,-0.14],[-3,0.7],[-3.7,-2]],"v":[[-11.166,-19.585],[-11.927,7.863],[-8.625,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[14.152,-8.699],[8.332,-14.539],[-4.768,-13.439]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":52,"s":[{"i":[[0.662,-3.59],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-2.532,4.395],[2.352,1.824],[4.412,1.481]],"o":[[-1.585,8.587],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.006,-0.084],[-3.613,-2.802],[-3.581,-1.202]],"v":[[-11.303,-19.608],[-12.133,7.863],[-8.83,12.562],[0.35,14.211],[9.404,12.616],[12.749,7.749],[13.232,-10.927],[9.315,-14.243],[-5.266,-16.412]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[1.056,-3.495],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-3.19,3.944],[2.33,2.05],[4.563,1.956]],"o":[[-2.702,8.946],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.021,-0.037],[-3.578,-3.149],[-3.704,-1.587]],"v":[[-11.164,-19.885],[-11.927,7.863],[-8.625,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[14.152,-8.699],[10.308,-12.326],[-4.786,-14.983]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.6,"y":0},"t":66,"s":[{"i":[[0.662,-3.59],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-2.532,4.395],[2.352,1.886],[4.412,1.589]],"o":[[-1.585,8.587],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.006,-0.084],[-3.613,-2.897],[-3.581,-1.29]],"v":[[-11.303,-20.208],[-12.133,7.863],[-8.83,12.562],[0.35,14.211],[9.404,12.616],[12.749,7.749],[13.232,-10.927],[9.315,-14.347],[-4.166,-15.759]],"c":false}]},{"i":{"x":0.13,"y":1},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0.229,-1.092],[0,0],[-1.89,-0.83],[-2.946,0],[-2.468,1.063],[-0.086,2.131],[-0.774,1.343],[2.54,0.846],[4.54,0.959]],"o":[[-0.964,4.6],[0.14,2.059],[2.504,1.099],[2.898,0],[1.959,-0.844],[0,0],[0.002,-0.026],[-3.902,-1.3],[-3.684,-0.778]],"v":[[-12.005,-18.139],[-12.127,7.863],[-8.825,12.562],[0.35,14.211],[9.398,12.616],[12.744,7.749],[13.275,-12.666],[9.02,-14.164],[-5.367,-14.041]],"c":false}]},{"t":94,"s":[{"i":[[0,0],[-0.741,-5.903],[-1.922,-0.751],[-2.946,0],[-2.468,1.063],[-0.228,3.004],[0,0],[0,0],[0,0]],"o":[[0,0],[0.328,2.608],[2.556,0.999],[2.898,0],[1.959,-0.844],[0.638,-8.388],[0,0],[0,0],[0,0]],"v":[[-12.432,-14.575],[-11.977,8.464],[-8.487,13.499],[0.4,14.598],[9.223,13.566],[12.656,8.149],[12.482,-13.225],[8.179,-13.458],[-3.728,-14.103]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"hand_4","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[29.062,27.773,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[11.426,11.426,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":420,"op":540,"st":420,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"hand_3","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[29.062,27.773,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[11.426,11.426,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":240,"op":420,"st":240,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"hand_2","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[29.062,27.773,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[11.426,11.426,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":120,"op":240,"st":120,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"hand_1","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[29.062,27.773,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[11.426,11.426,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":120,"st":0,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/calls/voice.lottie ================================================ {"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":404,"w":60,"h":60,"nm":"ALL","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[13.6,13.6,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":29,"st":0,"bm":0}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"START","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[282.33,256.042,0],"to":[0,0,0],"ti":[0,0,0]},{"t":7,"s":[254.33,256.042,0]}],"ix":2},"a":{"a":0,"k":[12.33,0.042,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.27,"y":0},"t":0,"s":[{"i":[[2.8,-1.7],[0,0],[5.7,9.5],[0,3.6],[0,0],[-11.1,0],[-3.1,-1.9],[0,0],[5.7,-9.4]],"o":[[0,0],[-9.4,5.7],[-1.9,-3.1],[0,0],[0,-11],[3.6,0],[0,0],[9.4,5.7],[-1.7,2.7]],"v":[[103.4,17.1],[-58.1,114.7],[-85.5,107.9],[-88.4,97.6],[-88.4,-97.6],[-68.4,-117.5],[-58.1,-114.6],[103.4,-17],[110.2,10.4]],"c":true}]},{"t":10,"s":[{"i":[[5.225,-7.477],[6.6,-2.2],[5.7,9.5],[0,3.6],[-0.127,11.332],[-7.35,7.25],[-5.65,0.1],[-14.675,-17.878],[0.55,-11.25]],"o":[[-6.15,8.8],[-7.202,2.401],[-1.9,-3.1],[0,0],[0.15,-13.4],[2.563,-2.528],[0,0],[7.1,8.65],[-0.2,7.75]],"v":[[36.4,28.7],[15.4,39.95],[-11,30.15],[-16.4,18.1],[-18.65,0.9],[-8.65,-24],[7.4,-31.85],[36.15,-20.4],[43.7,7.5]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Triangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":5,"st":-6,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Leg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252.45,380.6,0],"ix":2},"a":{"a":0,"k":[-3.55,124.6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.31,"y":0},"t":5,"s":[{"i":[[-6.3,0],[0,0],[0,-1.435],[0,0],[6.3,0],[0,0],[0,1.435],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,1.435],[0,0],[-6.3,0],[0,0],[0,-1.435]],"v":[[-5.2,78.5],[-1.9,78.5],[9.5,81.097],[9.5,86.403],[-1.9,89],[-5.2,89],[-16.6,86.403],[-16.6,81.097]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":13,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.15,70.5],[-1.85,70.5],[9.55,81.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.55,81.9]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":22,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.15,86.75],[-1.85,86.75],[9.55,98.15],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.55,98.15]],"c":true}]},{"t":29,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.2,78.5],[-1.9,78.5],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":7,"op":30,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arc R","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[66.05,51.45,0],"ix":2},"a":{"a":0,"k":[66.05,51.45,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.31,"y":0},"t":8,"s":[{"i":[[0,0],[35.3,-21.739]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[36.7,75]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[14.8,-11.381]],"o":[[0.03,17.185],[0,0]],"v":[[78.7,5.25],[62.7,54.175]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[15.195,-13.612]],"o":[[0.075,19.589],[0,0]],"v":[[79.155,2.974],[63.805,52.795]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[9.715,-14.875]],"o":[[0.094,20.585],[0,0]],"v":[[79.372,1.136],[64.285,50.377]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[9.715,-14.875]],"o":[[0.094,20.585],[0,0]],"v":[[79.372,1.136],[64.285,50.377]],"c":false}]},{"t":23,"s":[{"i":[[0,0],[8.7,-12]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[64.7,50.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.711],"y":[6.356]},"o":{"x":[0.392],"y":[0]},"t":8,"s":[100]},{"i":{"x":[0.66],"y":[0.822]},"o":{"x":[0.353],"y":[0.153]},"t":9,"s":[100]},{"i":{"x":[0.544],"y":[0.863]},"o":{"x":[0.254],"y":[0.3]},"t":10,"s":[57.213]},{"i":{"x":[0.564],"y":[1]},"o":{"x":[0.246],"y":[0.217]},"t":12,"s":[19.305]},{"t":15,"s":[0]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5,"op":30,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arc L","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.31,"y":0},"t":3,"s":[-3.75,84.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":13,"s":[-3.75,77.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":22,"s":[-3.75,87.25,0],"to":[0,0,0],"ti":[0,0,0]},{"t":29,"s":[-3.75,84.5,0]}],"ix":2},"a":{"a":0,"k":[-3.75,84.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.31,"y":0},"t":5,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":15,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85,2]],"c":false}]},{"t":23,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.31],"y":[0]},"t":5,"s":[15]},{"t":15,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.723],"y":[5.239]},"o":{"x":[0.4],"y":[0]},"t":5,"s":[15]},{"i":{"x":[0.695],"y":[0.969]},"o":{"x":[0.368],"y":[0.188]},"t":7,"s":[15]},{"t":8,"s":[0]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5,"op":30,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Line","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[3.687,-6.898,0],"ix":2},"a":{"a":0,"k":[3.6,-7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.31,"y":0},"t":5,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.613,-97],[108.787,112]],"c":false}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.213,-118.069],[115.413,104.069]],"c":false}]},{"t":23,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.6,-111.5],[108.8,97.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.31],"y":[0]},"t":5,"s":[34]},{"t":15,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.31],"y":[0]},"t":5,"s":[59]},{"t":15,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-10","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5,"op":30,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Head","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.6,-33.55,0],"ix":2},"a":{"a":0,"k":[-3.6,-33.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.31,"y":0},"t":3,"s":[{"i":[[-25.4,0],[0,-14.432],[0,0],[12.95,-6.477],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,6.477],[0,0],[0,0],[0,0],[0,-14.432]],"v":[[-3.6,-45],[42.4,-18.863],[42.4,24.32],[23.55,44.576],[-27.58,17.939],[-49.7,3.439],[-49.6,-18.863]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[-25.217,0],[0,-18.82],[0,0],[12.857,-8.447],[0,0],[0,0],[0,0]],"o":[[25.217,0],[0,0],[0,8.447],[0,0],[0,0],[0,0],[0,-18.82]],"v":[[-3.6,-74.003],[42.068,-39.92],[42.068,16.391],[23.354,42.805],[-22.609,2.243],[-49.345,-21.035],[-49.269,-39.92]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[-25.133,0],[0,-20.833],[0,0],[7.486,-6.386],[0,0],[0,0],[0,0]],"o":[[25.133,0],[0,0],[0,9.35],[0,0],[0,0],[0,0],[0,-20.833]],"v":[[-3.601,-87.309],[41.916,-49.58],[41.916,12.754],[28.014,36.493],[-16.079,-7.707],[-49.113,-39.513],[-49.117,-49.58]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[-24.994,0],[0,-24.173],[0,0],[9.026,-7.804],[0,0],[0,0],[0,0]],"o":[[24.994,0],[0,0],[0,10.849],[0,0],[0,0],[0,0],[0,-24.173]],"v":[[-3.601,-109.388],[41.663,-65.611],[41.663,6.718],[27.287,33.135],[-21.692,-14.203],[-48.939,-44.406],[-48.865,-65.611]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":13,"s":[{"i":[[-24.882,0],[0,-26.136],[0,0],[6.004,-6.398],[0,0],[0,0],[0,0]],"o":[[24.882,0],[0,0],[0,11.73],[0,0],[0,0],[0,0],[0,-26.136]],"v":[[-3.601,-123],[41.462,-75.667],[41.462,2.534],[30.496,26.07],[-20.343,-23.873],[-48.773,-48.671],[-48.664,-75.667]],"c":true}]},{"t":22,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[6.9,-8],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[31.3,34.4],[-20.33,-17.23],[-49.6,-46.5],[-49.6,-71.5]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.31,"y":0},"t":3,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,14.432],[0,0]],"o":[[0,0],[0,0],[0,0],[-11.85,5.796],[-25.4,0],[0,0],[0,0]],"v":[[-49.7,1.365],[-24.952,12.671],[-23,13.78],[26.35,43.241],[-3.6,50.4],[-49.6,24.263],[-49.7,1.365]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.857,0],[0,18.82],[0,0]],"o":[[0,0],[0,0],[0,0],[-11.765,7.558],[-25.217,0],[0,0],[0,0]],"v":[[-49.345,-23.74],[-20,-4.627],[-18.062,-3.18],[26.134,41.064],[-3.6,50.4],[-49.269,16.317],[-49.345,-23.74]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.838,0],[0,20.833],[0,0]],"o":[[0,0],[0,0],[0,0],[-10.035,6.292],[-25.133,0],[0,0],[0,0]],"v":[[-49.113,-23.507],[-25.728,0.688],[-23.796,2.289],[19.285,43.816],[-3.601,50.4],[-49.117,12.672],[-49.113,-23.257]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.806,0],[0,24.173],[0,0]],"o":[[0,0],[0,0],[0,0],[-6.163,2.551],[-24.994,0],[0,0],[0,0]],"v":[[-49.382,-11.516],[-31.116,7.197],[-29.195,9.055],[8.663,46.861],[-3.601,50.4],[-48.865,6.622],[-49.243,-11.446]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":13,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.78,0],[0,26.837],[0,0]],"o":[[0,0],[0,0],[0,0],[-4.239,1.413],[-24.882,0],[0,0],[0,0]],"v":[[-48.796,-13.783],[-30.018,6.241],[-28.105,8.304],[9.739,46.087],[-3.601,50.4],[-48.664,1.797],[-48.546,-13.658]],"c":true}]},{"t":22,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.2,2],[-25.4,0],[0,0],[0,0]],"v":[[-49.6,-15.4],[-40.702,-6.502],[-38.75,-4.55],[13.1,47.3],[-3.6,50.4],[-49.6,4.4],[-49.6,-15.4]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":30,"st":0,"bm":0}]},{"id":"comp_2","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[13.6,13.6,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":33,"st":0,"bm":0}]},{"id":"comp_3","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Line","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[3.687,-6.898,0],"ix":2},"a":{"a":0,"k":[3.6,-7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.2,"y":0},"t":14,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.6,-111.5],[108.8,97.5]],"c":false}]},{"t":26,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.6,-111.5],[108.8,97.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":14,"s":[14]},{"t":26,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":14,"s":[86]},{"t":26,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-10","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":34,"st":-1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Head","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.6,-33.55,0],"ix":2},"a":{"a":0,"k":[-3.6,-33.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-25.4,0],[0,-25.4],[0,0],[6.9,-8],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[31.3,34.4],[-20.33,-17.23],[-49.6,-46.5],[-49.6,-71.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.2,2],[-25.4,0],[0,0],[0,0]],"v":[[-49.6,-15.4],[-40.702,-6.502],[-38.75,-4.55],[13.1,47.3],[-3.6,50.4],[-49.6,4.4],[-49.6,-15.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":34,"st":-1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arc L","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.31,"y":0},"t":13,"s":[-3.75,69.094,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":25,"s":[-3.75,89.094,0],"to":[0,0,0],"ti":[0,0,0]},{"t":33,"s":[-3.75,84.5,0]}],"ix":2},"a":{"a":0,"k":[-3.75,84.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.29,"y":0},"t":17,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false}]},{"t":27,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.723],"y":[0.572]},"o":{"x":[0.4],"y":[0]},"t":4,"s":[15]},{"i":{"x":[0.695],"y":[0.627]},"o":{"x":[0.368],"y":[0.45]},"t":6,"s":[29]},{"i":{"x":[0.323],"y":[1]},"o":{"x":[0.222],"y":[0.388]},"t":7,"s":[37.868]},{"t":17,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.723],"y":[1.14]},"o":{"x":[0.4],"y":[0]},"t":4,"s":[12]},{"i":{"x":[0.695],"y":[0.945]},"o":{"x":[0.368],"y":[0.061]},"t":6,"s":[17.559]},{"i":{"x":[0.652],"y":[0.857]},"o":{"x":[0.357],"y":[0.122]},"t":7,"s":[9]},{"i":{"x":[0.426],"y":[1]},"o":{"x":[0.183],"y":[-2.717]},"t":9,"s":[0]},{"t":17,"s":[0]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":6,"op":34,"st":-1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arc R","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[66.05,51.45,0],"ix":2},"a":{"a":0,"k":[66.05,51.45,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.29,"y":0},"t":17,"s":[{"i":[[0,0],[8.7,-12]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[64.7,50.5]],"c":false}]},{"t":27,"s":[{"i":[[0,0],[8.7,-12]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[64.7,50.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":7,"s":[99]},{"t":17,"s":[0]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":10,"op":34,"st":-1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Leg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252.45,380.6,0],"ix":2},"a":{"a":0,"k":[-3.55,124.6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.31,"y":0},"t":13,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.15,64],[-1.85,64],[9.55,75.4],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.55,75.4]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":25,"s":[{"i":[[-6.3,0],[0,0],[0,-2.846],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-2.846]],"v":[[-5.2,84.75],[-1.9,84.75],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true}]},{"t":33,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.2,78.5],[-1.9,78.5],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":9,"op":34,"st":-1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Line Bell","parent":7,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.28,"y":0},"t":-1,"s":[5.03,-9.859,0],"to":[0,0,0],"ti":[0,0,0]},{"t":14,"s":[4.03,-8.359,0]}],"ix":2},"a":{"a":0,"k":[-0.05,-2.95,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-98.152,-101.129],[98.052,95.229]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.28],"y":[0]},"t":-1,"s":[0]},{"t":14,"s":[12]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.28],"y":[0]},"t":-1,"s":[100]},{"t":14,"s":[88]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":14,"st":-1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Bell","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":-1,"s":[258.564,256.028,0],"to":[0,0,0],"ti":[0,0,0]},{"t":13,"s":[253.564,241.028,0]}],"ix":2},"a":{"a":0,"k":[-1.88,-0.927,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.5,"y":0},"t":-1,"s":[{"i":[[-4.2,9.7],[0,0],[0,0],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-74.4,-46.7],[32.121,59.821],[34.778,62.478],[51.9,79.6],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"t":13,"s":[{"i":[[-0.557,1.753],[0,0],[0,0],[0,0],[12.242,3.875],[4.463,6.051],[0,0],[0,0],[0,1.225],[0.586,4.254],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-8.598,-2.722],[0,0],[0,0],[-0.69,-2.075],[0,0],[-1.67,-12.113],[0.086,-1.777]],"v":[[-48.888,-16.333],[2.602,35.024],[4.48,36.832],[14.055,46.983],[-15.561,47.733],[-39.407,31.182],[-39.266,30.978],[-44.13,22.682],[-46.406,17.666],[-48.156,11.291],[-49.281,-8.366]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.5,"y":0},"t":-1,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[10.111,-11.873],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[10.58,-1.555]],"v":[[88.55,58.6],[73.795,40.25],[71.995,35.45],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-62.4,-65.9],[-19.568,-22.503],[-18.761,-21.685],[79.699,78.074],[80.6,78.975]],"c":true}]},{"t":13,"s":[{"i":[[-2.182,4.07],[-1.1,3.295],[0,1.8],[0,0],[25.933,14.308],[0,0],[11.842,-0.367],[0,0],[3.626,-2.33],[0,0],[-2.875,-21.055],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0.815,-2.442],[0,0],[0.221,-54.605],[0,0],[-4.442,-2.455],[0,0],[-13.97,-0.305],[0,0],[-19.874,13.29],[0,0],[0,0],[0,0],[0,0],[2.995,-3.055]],"v":[[36.363,27.6],[40.655,19.625],[42.779,11.2],[43.21,-19.85],[21.372,-111.763],[20.684,-112.312],[-3.286,-118.838],[-3.6,-118.9],[-29.821,-110.375],[-31.571,-108.995],[-48.57,-47.15],[-22.056,-18.753],[-21.467,-17.935],[30.402,32.574],[31.31,33.225]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":12,"st":-1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Bottom Bell","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[255.445,394.655,0],"ix":2},"a":{"a":0,"k":[0,137.7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":-1,"s":[{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.1]],"v":[[0.5,119.605],[26.1,97.805],[22.8,93.605],[-20.9,93.605],[-25.2,97.405]],"c":true}]},{"t":9,"s":[{"i":[[-8.162,0],[0.625,15.53],[0.51,0.546],[4.907,-5.5],[0.14,-2.002]],"o":[[7.975,0],[0.125,-2.157],[-6.069,-6.5],[-0.373,0.418],[-1.164,16.646]],"v":[[-3.269,123.85],[10.181,105.515],[9.694,64.545],[-15.782,65.045],[-16.531,104.149]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":9,"st":-1,"bm":0}]},{"id":"comp_4","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[13.6,13.6,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":33,"st":0,"bm":0}]},{"id":"comp_5","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"EXAMPLE ON 2","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.981,2.44,0],"ix":2},"a":{"a":0,"k":[-0.038,1.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.1,0],[0,0],[0,-9.1],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[9,0],[0,0],[0,0],[0,0],[0,0],[0,-9.1]],"v":[[-1.6,-115.5],[-0.4,-115.5],[16,-99.1],[16,-89.5],[16,-89.5],[-18,-89.5],[-18,-99.1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.2]],"v":[[0,118.5],[25.6,96.7],[22.3,92.5],[-21.4,92.5],[-25.7,96.3]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,1.8],[0,0],[0,0],[36.4,8.6],[3.4,0],[5.9,-0.1],[0,-38.8],[0,0],[1.2,-1.3],[0,0],[0,0],[-11.3,0],[0,0],[8.1,7.9],[0,0]],"o":[[0,0],[0,0],[0,-38.6],[-6.7,-0.2],[-3,0],[-36.5,8.6],[0,0],[0,1.8],[0,0],[0,0],[-8,7.9],[0,0],[11.3,0],[0,0],[-1.1,-1.3]],"v":[[76.4,35.6],[76.4,-15.7],[76.4,-15.7],[14.3,-93.3],[-0.8,-93.5],[-14.2,-93.3],[-76.3,-15.7],[-76.3,35.6],[-78.1,40.4],[-92.8,57],[-92.8,57],[-81.5,78.5],[81.3,78.5],[92.7,57],[78.1,40.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Combined-Shape","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":15,"op":33,"st":-1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Line Bell","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":2,"s":[5.03,-9.859,0],"to":[0,0,0],"ti":[0,0,0]},{"t":23,"s":[12.954,-0.45,0]}],"ix":2},"a":{"a":0,"k":[-0.05,-2.95,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-98.152,-101.129],[98.052,95.229]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":2,"s":[0]},{"t":23,"s":[100]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":21,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Bottom Bell","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,137.7,0],"ix":2},"a":{"a":0,"k":[0,137.7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.1]],"v":[[-4.5,119.6],[21.1,97.8],[17.8,93.6],[-25.9,93.6],[-30.2,97.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":15,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Bell","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[260.562,232.132,0],"ix":2},"a":{"a":0,"k":[0.12,-24.927,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":12,"s":[93,93,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":22,"s":[101,101,100]},{"t":32,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[-4.2,9.7],[0,0],[0,0],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-74.4,-46.7],[32.121,59.821],[34.778,62.478],[51.9,79.6],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[-14.003,15.695],[-5.659,-3.648],[-10.756,-14.742],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[-6.594,-3.203],[4.9,6.715],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-63.408,-63.817],[-47.235,-56.249],[-60.858,-34.829],[50.693,79.614],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[-14.003,15.695],[-5.659,-3.648],[-10.756,-14.742],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[-6.594,-3.203],[4.9,6.715],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-63.408,-63.817],[-24.266,-35.672],[-39.752,-12.387],[50.693,79.614],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[-14.003,15.695],[-5.659,-3.648],[-10.756,-14.742],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[-6.594,-3.203],[4.9,6.715],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-63.408,-63.817],[-3.42,-13.502],[-18.646,10.055],[50.693,79.614],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[-14.003,15.695],[-5.659,-3.648],[-10.756,-14.742],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[-6.594,-3.203],[4.9,6.715],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-63.408,-63.817],[39.053,27.896],[23.827,51.453],[50.693,79.614],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[-14.003,15.695],[-5.659,-3.648],[-10.756,-14.742],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[-6.594,-3.203],[4.9,6.715],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-63.408,-63.817],[52.725,43.176],[39.376,66.197],[50.693,79.614],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[-14.003,15.695],[-5.659,-3.648],[-7.11,-19.386],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[-6.594,-3.203],[1.271,3.465],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-63.408,-63.817],[67.899,50.896],[48.96,73.385],[50.693,79.614],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"t":15,"s":[{"i":[[-7.545,13.495],[0,0],[0,0],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-68.9,-57.2],[46.687,58.223],[49.57,61.102],[68.15,79.655],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[10.111,-11.873],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[10.58,-1.555]],"v":[[88.55,58.6],[73.795,40.25],[71.995,35.45],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-62.4,-65.9],[-19.568,-22.503],[-18.761,-21.685],[79.699,78.074],[80.6,78.975]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[9.92,-13.055],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[9.935,-1.566]],"v":[[88.675,58.537],[73.795,40.125],[71.995,35.325],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-64.104,-63.629],[-25.68,-45.311],[-14.342,-27.377],[81.753,76.333],[80.85,79.006]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[9.92,-13.055],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[9.935,-1.566]],"v":[[88.675,58.537],[73.795,40.125],[71.995,35.325],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-64.104,-63.629],[7.983,-0.159],[27.87,17.507],[81.753,76.333],[80.85,79.006]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[9.92,-13.055],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[9.935,-1.566]],"v":[[88.675,58.537],[73.795,40.125],[71.995,35.325],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-64.104,-63.629],[50.456,41.238],[70.343,58.905],[81.753,76.333],[80.85,79.006]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[9.92,-13.055],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[9.935,-1.566]],"v":[[88.675,58.537],[73.795,40.125],[71.995,35.325],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-64.104,-63.629],[51.394,43.785],[70.343,58.905],[81.753,76.333],[80.85,79.006]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[9.92,-13.055],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[9.935,-1.566]],"v":[[88.675,58.537],[73.795,40.125],[71.995,35.325],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-64.104,-63.629],[66.569,51.505],[70.343,58.905],[81.753,76.333],[80.85,79.006]],"c":true}]},{"t":15,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[9.346,-16.6],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[8,-1.6]],"v":[[89.05,58.35],[73.795,39.75],[71.995,34.95],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-69.215,-56.816],[-28.207,-15.716],[-27.434,-14.941],[66.835,79.54],[81.6,79.1]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":15,"st":0,"bm":0}]},{"id":"comp_6","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[30,30,0],"to":[0,0,0],"ti":[0,0,0]},{"t":10,"s":[28.282,29.857,0]}],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[13.6,13.6,100]},{"t":10,"s":[13.5,13.5,100]}],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":37,"st":0,"bm":0}]},{"id":"comp_7","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Head 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[0.613,-101.537,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[11.613,-50.537,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":26,"s":[11.613,-89.537,0],"to":[0,0,0],"ti":[0,0,0]},{"t":36,"s":[11.113,-83.037,0]}],"ix":2},"a":{"a":0,"k":[11.613,-84.537,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0,-8.774],[8.774,0],[0,8.774],[-8.774,0]],"o":[[0,8.774],[-8.774,0],[0,-8.774],[8.774,0]],"v":[[25.5,-84.537],[9.613,-68.65],[-6.274,-84.537],[9.613,-100.424]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,-11.72],[13.247,0],[0,11.72],[-13.247,0]],"o":[[0,11.72],[-13.247,0],[0,-11.72],[13.247,0]],"v":[[33.09,-69.693],[9.103,-48.473],[-14.883,-69.693],[9.103,-90.913]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[0,-24.735],[24.735,0],[0,24.735],[-24.735,0]],"o":[[0,24.735],[-24.735,0],[0,-24.735],[24.735,0]],"v":[[56.4,-84.537],[11.613,-39.75],[-33.174,-84.537],[11.613,-129.324]],"c":true}]},{"t":25,"s":[{"i":[[0,-26.924],[26.924,0],[0,26.924],[-26.924,0]],"o":[[0,26.924],[-26.924,0],[0,-26.924],[26.924,0]],"v":[[60.363,-84.537],[11.613,-35.787],[-37.137,-84.537],[11.613,-133.287]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Hands 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.05,"y":0},"t":9,"s":[11.336,13.774,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.31,"y":0},"t":12,"s":[11.336,18.274,0],"to":[0,0,0],"ti":[0,0,0]},{"t":25,"s":[11.336,11.774,0]}],"ix":2},"a":{"a":0,"k":[11.336,10.774,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":7,"s":[{"i":[[0,0],[0.875,44.36],[0.012,11.61]],"o":[[0,0],[-0.348,-17.658],[-0.016,-14.955]],"v":[[-33.583,109.659],[-40.875,50.64],[-45.012,-17.11]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[-7.48,30.25],[-7.964,9.648]],"o":[[0,0],[2.73,-11.373],[7.228,-11.196]],"v":[[-57.163,97.688],[-57.996,36.651],[-42.036,0.102]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[-14.611,30.379],[-23.925,1.795]],"o":[[0,0],[7.389,-12.121],[13.171,-8.112]],"v":[[-77.526,99.758],[-81.889,29.906],[-41.075,4.99]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[0,0],[-27.718,19.589],[-10.136,-1.028]],"o":[[0,0],[21.782,-16.411],[19.114,-5.028]],"v":[[-107.888,77.829],[-93.782,16.161],[-42.114,8.877]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[0,0],[-27.325,4.127],[-14.975,-3.949]],"o":[[0,0],[20.334,-3.734],[35.444,0.066]],"v":[[-136.225,32.858],[-90.834,7.893],[-38.525,10.472]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[-27.129,-3.603],[-14.269,-4.157]],"o":[[0,0],[19.61,2.605],[43.609,2.613]],"v":[[-147.393,-5.627],[-89.61,-2.992],[-38.231,9.77]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[-38.825,-22.336],[-19.04,-2.789]],"o":[[0,0],[14.675,9.164],[62.76,8.586]],"v":[[-144.801,-73.381],[-91.175,-7.197],[-37.96,10.757]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[-46.458,-35.583],[-19.738,-3.567]],"o":[[0,0],[8.352,6.397],[79.039,14.286]],"v":[[-142.333,-130.341],[-88.062,-16.235],[-40.512,7.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":7,"s":[{"i":[[0,0],[0.583,25.777],[4.5,19.11]],"o":[[0,0],[-0.238,-10.518],[-18.41,-78.181]],"v":[[63,101.64],[63.167,54.973],[56,-16.61]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[2.455,25.149],[6.868,13.265]],"o":[[0,0],[-0.66,-9.745],[-29.265,-65.813]],"v":[[68.548,94.42],[70.368,48.723],[56.521,2.29]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[-11.495,10.995],[15.537,39.692],[11.504,1.535]],"o":[[14.034,-13.424],[-3.378,-8.551],[-47.075,-45.52]],"v":[[79.466,115.674],[91.463,38.058],[62.496,12.174]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[-14.54,10.097],[25.244,37.544],[12.466,1.965]],"o":[[15.872,-11.198],[-4.741,-7.952],[-56.007,-35.342]],"v":[[88.294,117.357],[93.089,33.781],[63.701,13.504]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[-16.063,9.648],[30.097,36.471],[11.946,0.457]],"o":[[16.791,-10.086],[-5.422,-7.653],[-60.473,-30.253]],"v":[[92.709,118.199],[93.903,31.642],[61.554,13.67]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[-5.509,3.309],[41.86,36.38],[11.653,0.923]],"o":[[5.759,-3.459],[-7.371,-6.796],[-73.243,-15.702]],"v":[[124.602,127.851],[94.405,26.111],[62.332,13.5]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":25,"s":[{"i":[[0,0],[48,36.333],[11.5,1.167]],"o":[[0,0],[-8.388,-6.35],[-79.91,-8.107]],"v":[[141.25,132.89],[94.667,23.223],[63.5,11.89]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[48,36.333],[11.5,1.167]],"o":[[0,0],[-8.388,-6.35],[-79.91,-8.107]],"v":[[140,128.89],[94.667,23.848],[63.5,11.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":9,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Body 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[266.676,398.378,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":23,"s":[266.676,387.378,0],"to":[0,0,0],"ti":[0,0,0]},{"t":34,"s":[266.676,392.378,0]}],"ix":2},"a":{"a":0,"k":[10.676,136.378,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.69,"y":1},"o":{"x":0.31,"y":0},"t":12,"s":[{"i":[[-12.288,0.098],[-12.498,-0.987],[0,0],[3.339,-1.222],[4.897,-9.213],[22.369,0],[7.456,13.82],[-1.892,54.808]],"o":[[8.847,-0.071],[35.724,2.82],[24.706,0],[0,0],[-7.456,13.82],[-22.369,0],[-4.897,-9.213],[-12.353,-3.008]],"v":[[-46.407,7.071],[-18.334,9.585],[61.794,9.679],[70.141,28.952],[68.805,121.176],[13.161,136.5],[-42.484,121.176],[-47.047,25.191]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.31,"y":0},"t":23,"s":[{"i":[[-10.8,-2.3],[-8.2,-0.4],[0,0],[3,-1.3],[4.4,-9.8],[20.1,0],[6.7,14.7],[-1.7,58.3]],"o":[[7.9,1.7],[0,0],[22.2,0],[0,0],[-6.7,14.7],[-20.1,0],[-4.4,-9.8],[-11.1,-3.2]],"v":[[-40.2,-2.3],[-15.1,1.5],[56.9,1.6],[64.4,22.1],[63.2,120.2],[13.2,136.5],[-36.8,120.2],[-40.9,18.1]],"c":true}]},{"t":34,"s":[{"i":[[-10.8,-2.3],[-8.2,-0.4],[0,0],[3,-1.3],[4.4,-9.8],[24.175,0.094],[6.7,14.7],[-1.7,58.3]],"o":[[7.9,1.7],[0,0],[22.2,0],[0,0],[-6.669,14.144],[-20.1,-0.078],[-4.4,-9.8],[-11.1,-3.2]],"v":[[-40.2,-2.3],[-15.1,1.5],[56.9,1.6],[64.4,22.1],[63.044,119.606],[13.2,136.156],[-36.8,120.2],[-40.9,18.1]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Line Bell","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[264.975,247.096,0],"to":[0,0,0],"ti":[0,0,0]},{"t":12,"s":[260.475,307.096,0]}],"ix":2},"a":{"a":0,"k":[-0.05,-2.95,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-98.152,-101.129],[98.052,95.229]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":0,"s":[0]},{"t":12,"s":[45]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":0,"s":[100]},{"t":12,"s":[69]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Bell","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[260.467,231.7,0],"to":[0,0,0],"ti":[0,0,0]},{"t":12,"s":[255.967,270.7,0]}],"ix":2},"a":{"a":0,"k":[-0.033,-25.3,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-4.2,9.7],[0,0],[0,0],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-74.4,-46.7],[32.121,59.821],[34.778,62.478],[51.9,79.6],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[-8.362,11.23],[0,0],[0,0],[3.762,-1.859],[8.142,-0.264],[0.777,8.157],[0.156,0.224],[1.314,3.134],[0.224,1.943],[0,0],[-0.582,7.711]],"o":[[0,0],[0,0],[0,0],[-19.321,9.547],[-28.463,-1.013],[-0.005,-0.156],[-0.156,-3.776],[0.062,-2.373],[0,0],[-0.045,-4.946],[0,-7.124]],"v":[[-60.638,-49.681],[29.345,35.402],[55.841,63.676],[71.571,79.252],[-31.443,86.874],[-68.777,71.642],[-68.75,71.544],[-67.843,58.677],[-67.812,51.954],[-68.27,48.401],[-68.748,-3.168]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[-1.323,3.262],[0,0],[0,0],[6.275,-3.565],[14.005,-0.455],[0.542,0.356],[1.713,1.084],[2.26,5.391],[0.385,2.046],[0,0],[-1.001,13.264]],"o":[[0,0],[0,0],[0,0],[-4.624,2.627],[-40.891,-1.743],[0.542,-0.578],[-4.048,-2.564],[-0.758,-3.145],[0,0],[-0.077,-8.507],[0,-3.901]],"v":[[-57.609,-43.228],[22.617,23.841],[64.126,70.129],[61.225,80.722],[7.766,92.111],[-48.042,81.338],[-48.213,81.277],[-57.218,71.044],[-58.46,62.937],[-59.249,56.826],[-60.071,5.063]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[-0.309,0.762],[0,0],[0,0],[4.568,-5.804],[17.516,-1.439],[9.846,0.175],[5.202,1.836],[3.057,6.91],[0.521,1.988],[0,0],[-1.354,17]],"o":[[0,0],[0,0],[0,0],[-4.183,5.585],[-15.234,1.811],[-9.592,-0.227],[-5.947,-2.247],[-1.448,-3.573],[0,0],[-0.104,-10.903],[0,-0.911]],"v":[[-52.53,-28.79],[11.994,25.222],[67.477,74.382],[64.512,86.679],[25.234,99.127],[-10.469,99.989],[-34.862,95.528],[-48.272,82.948],[-50.586,74.249],[-51.653,66.417],[-52.765,18.153]],"c":true}]},{"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[4.244,-6.392],[19.61,-0.621],[11.618,0.122],[6.498,1.941],[3.306,7.372],[0.563,1.97],[0,0],[-1.464,18.138]],"o":[[0,0],[0,0],[0,0],[-4.244,6.392],[-5.683,0.18],[-11.618,-0.122],[-6.595,-1.969],[-1.661,-3.704],[0,0],[-0.113,-11.633],[0,0]],"v":[[-46.474,-23.891],[12.383,25.893],[71.24,75.677],[67.655,88.306],[34.655,101.868],[5.941,102.334],[-23.997,99.619],[-42.777,86.574],[-45.423,77.695],[-46.577,69.338],[-47.779,22.141]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[10.111,-11.873],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[10.58,-1.555]],"v":[[88.55,58.6],[73.795,40.25],[71.995,35.45],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-62.4,-65.9],[-19.568,-22.503],[-18.761,-21.685],[79.699,78.074],[80.6,78.975]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0.157,8.024],[0,0],[0,1.922],[0,0],[24.177,-0.77],[0,0],[9,0],[0,0],[5.709,0.272],[0,0],[-0.26,-17.504],[0,0],[0,0],[0,0],[-7.459,5.266]],"o":[[0,0],[-0.323,-1.991],[0,0],[1.096,-24.22],[0,0],[-9.573,2.118],[0,0],[-9.1,0],[0,0],[-6.6,1.142],[0,0],[0,0],[0,0],[0,0],[3.993,-2.819]],"v":[[71.843,56.59],[71.106,36.657],[70.583,30.009],[69.845,-21.987],[38.823,-52.309],[28.073,-50.661],[3.062,-46.678],[1.048,-46.86],[-26.209,-52.017],[-31.319,-53.002],[-58.24,-38.393],[-25.737,-8.451],[-22.131,-4.064],[59.51,80.628],[65.709,78.296]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0.094,4.576],[0,0],[0,1.828],[0,0],[20.355,-2.421],[0,0],[9,0],[0,0],[6.507,0.351],[0,0],[2.835,-13.717],[0,0],[0,0],[0,0],[-1.742,1.23]],"o":[[0,0],[-0.014,-2.094],[0,0],[-0.871,-19.045],[0,0],[-6.547,0.878],[0,0],[-9.1,0],[0,0],[-3.266,-0.12],[0,0],[0,0],[0,0],[0,0],[1.239,-8.208]],"v":[[69.031,57.556],[68.76,39.315],[68.408,33.605],[67.871,-20.767],[25.645,-36.641],[23.135,-36.246],[-0.875,-35.181],[-1.998,-35.415],[-22.891,-36.675],[-31.934,-38.285],[-52.647,-28.157],[-24.554,-1.976],[-21.081,1.4],[63.583,76.467],[67.733,76.517]],"c":true}]},{"t":12,"s":[{"i":[[0.075,3.525],[0,0],[0,1.8],[0,0],[24.798,0.638],[0,0],[9.018,0],[0,0],[6.763,0.375],[0,0],[-1.858,-4.475],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0.08,-2.125],[0,0],[1.607,-13.525],[0,0],[-5.636,0.5],[0,0],[-9.118,0],[0,0],[-2.254,-0.505],[0,0],[0,0],[0,0],[0,0],[0.401,-9.85]],"v":[[71.166,57.85],[71.036,40.125],[70.735,34.7],[70.643,-14.975],[22.897,-23.388],[22.897,-23.375],[0.453,-23.525],[0.253,-23.775],[-17.431,-24.5],[-24.068,-24.87],[-46.892,-24.4],[-21.382,-0.003],[-17.943,3.065],[67.559,75.199],[71.091,75.975]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Bottom Bell","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[0,136.7,0],"to":[0,0,0],"ti":[0,0,0]},{"t":12,"s":[12,91.7,0]}],"ix":2},"a":{"a":0,"k":[0,137.7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.1]],"v":[[-5.125,120.225],[20.6,99.05],[17.3,94.85],[-26.4,94.85],[-30.7,98.65]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[-19.183,0.659],[-2.93,11.67],[1.758,0],[29.45,0],[-0.296,-1.263]],"o":[[23.128,-0.795],[2.186,-3.703],[-15.091,0],[-1.319,0],[2.784,11.767]],"v":[[-2.487,124.469],[35.205,101.877],[29.62,99.793],[-34.409,99.793],[-40.709,103.488]],"c":true}]},{"t":12,"s":[{"i":[[-28.151,0],[-4.298,11.184],[2.579,0],[43.194,0],[-0.438,-1.209]],"o":[[27.506,0],[0.43,-1.305],[-22.134,0],[-1.934,0],[4.083,11.277]],"v":[[-0.461,137.5],[54.82,117.764],[47.729,113.85],[-46.18,113.85],[-55.42,117.392]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":0,"bm":0}]},{"id":"comp_8","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 2","refId":"comp_9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[30,30,0],"to":[0,0,0],"ti":[0,0,0]},{"t":10,"s":[28.282,29.857,0]}],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[13.6,13.6,100]},{"t":10,"s":[13.5,13.5,100]}],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":37,"st":0,"bm":0}]},{"id":"comp_9","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Head 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[0.613,-101.537,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[11.613,-50.537,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":26,"s":[11.613,-87.537,0],"to":[0,0,0],"ti":[0,0,0]},{"t":36,"s":[11.113,-83.037,0]}],"ix":2},"a":{"a":0,"k":[11.613,-84.537,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0,-8.774],[8.774,0],[0,8.774],[-8.774,0]],"o":[[0,8.774],[-8.774,0],[0,-8.774],[8.774,0]],"v":[[25.5,-84.537],[9.613,-68.65],[-6.274,-84.537],[9.613,-100.424]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,-11.72],[13.247,0],[0,11.72],[-13.247,0]],"o":[[0,11.72],[-13.247,0],[0,-11.72],[13.247,0]],"v":[[33.09,-69.693],[9.103,-48.473],[-14.883,-69.693],[9.103,-90.913]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[0,-24.735],[24.735,0],[0,24.735],[-24.735,0]],"o":[[0,24.735],[-24.735,0],[0,-24.735],[24.735,0]],"v":[[56.4,-84.537],[11.613,-39.75],[-33.174,-84.537],[11.613,-129.324]],"c":true}]},{"t":25,"s":[{"i":[[0,-26.924],[26.924,0],[0,26.924],[-26.924,0]],"o":[[0,26.924],[-26.924,0],[0,-26.924],[26.924,0]],"v":[[60.363,-84.537],[11.613,-35.787],[-37.137,-84.537],[11.613,-133.287]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Hands 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.05,"y":0},"t":9,"s":[11.336,13.774,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.31,"y":0},"t":12,"s":[11.336,18.274,0],"to":[0,0,0],"ti":[0,0,0]},{"t":25,"s":[11.336,11.774,0]}],"ix":2},"a":{"a":0,"k":[11.336,10.774,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":7,"s":[{"i":[[0,0],[0.875,44.36],[0.012,11.61]],"o":[[0,0],[-0.348,-17.658],[-0.016,-14.955]],"v":[[-33.583,109.659],[-40.875,50.64],[-45.012,-17.11]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[-7.48,30.25],[-7.964,9.648]],"o":[[0,0],[2.73,-11.373],[7.228,-11.196]],"v":[[-57.163,97.688],[-57.996,36.651],[-42.036,0.102]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[-14.611,30.379],[-23.925,1.795]],"o":[[0,0],[7.389,-12.121],[13.171,-8.112]],"v":[[-77.526,99.758],[-81.889,29.906],[-41.075,4.99]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[0,0],[-27.718,19.589],[-10.136,-1.028]],"o":[[0,0],[21.782,-16.411],[19.114,-5.028]],"v":[[-107.888,77.829],[-93.782,16.161],[-42.114,8.877]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[0,0],[-27.325,4.127],[-14.975,-3.949]],"o":[[0,0],[20.334,-3.734],[35.444,0.066]],"v":[[-136.225,32.858],[-90.834,7.893],[-38.525,10.472]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[-27.129,-3.603],[-14.269,-4.157]],"o":[[0,0],[19.61,2.605],[43.609,2.613]],"v":[[-147.393,-5.627],[-89.61,-2.992],[-38.231,9.77]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[-38.825,-22.336],[-19.04,-2.789]],"o":[[0,0],[14.675,9.164],[62.76,8.586]],"v":[[-144.801,-73.381],[-91.175,-7.197],[-37.96,10.757]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[-46.458,-35.583],[-19.738,-3.567]],"o":[[0,0],[8.352,6.397],[79.039,14.286]],"v":[[-142.333,-130.341],[-88.062,-16.235],[-40.512,7.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":7,"s":[{"i":[[0,0],[0.583,25.777],[4.5,19.11]],"o":[[0,0],[-0.238,-10.518],[-18.41,-78.181]],"v":[[63,101.64],[63.167,54.973],[56,-16.61]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[2.455,25.149],[6.868,13.265]],"o":[[0,0],[-0.66,-9.745],[-29.265,-65.813]],"v":[[68.548,94.42],[70.368,48.723],[56.521,2.29]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[-11.495,10.995],[15.537,39.692],[11.504,1.535]],"o":[[14.034,-13.424],[-3.378,-8.551],[-47.075,-45.52]],"v":[[79.466,115.674],[91.463,38.058],[62.496,12.174]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[-14.54,10.097],[25.244,37.544],[12.466,1.965]],"o":[[15.872,-11.198],[-4.741,-7.952],[-56.007,-35.342]],"v":[[88.294,117.357],[93.089,33.781],[63.701,13.504]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[-16.063,9.648],[30.097,36.471],[11.946,0.457]],"o":[[16.791,-10.086],[-5.422,-7.653],[-60.473,-30.253]],"v":[[92.709,118.199],[93.903,31.642],[61.554,13.67]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[-5.509,3.309],[41.86,36.38],[11.653,0.923]],"o":[[5.759,-3.459],[-7.371,-6.796],[-73.243,-15.702]],"v":[[124.602,127.851],[94.405,26.111],[62.332,13.5]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":25,"s":[{"i":[[0,0],[48,36.333],[11.5,1.167]],"o":[[0,0],[-8.388,-6.35],[-79.91,-8.107]],"v":[[141.25,132.89],[94.667,23.223],[63.5,11.89]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[48,36.333],[11.5,1.167]],"o":[[0,0],[-8.388,-6.35],[-79.91,-8.107]],"v":[[140,128.89],[94.667,23.848],[63.5,11.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":9,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Body 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[266.676,398.378,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":23,"s":[266.676,387.378,0],"to":[0,0,0],"ti":[0,0,0]},{"t":34,"s":[266.676,392.378,0]}],"ix":2},"a":{"a":0,"k":[10.676,136.378,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.69,"y":1},"o":{"x":0.31,"y":0},"t":12,"s":[{"i":[[-12.288,0.098],[-12.498,-0.987],[0,0],[3.339,-1.222],[4.897,-9.213],[22.369,0],[7.456,13.82],[-1.892,54.808]],"o":[[8.847,-0.071],[35.724,2.82],[24.706,0],[0,0],[-7.456,13.82],[-22.369,0],[-4.897,-9.213],[-12.353,-3.008]],"v":[[-46.407,7.071],[-18.334,9.585],[61.794,9.679],[70.141,28.952],[68.805,121.176],[13.161,136.5],[-42.484,121.176],[-47.047,25.191]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.31,"y":0},"t":23,"s":[{"i":[[-10.8,-2.3],[-8.2,-0.4],[0,0],[3,-1.3],[4.4,-9.8],[20.1,0],[6.7,14.7],[-1.7,58.3]],"o":[[7.9,1.7],[0,0],[22.2,0],[0,0],[-6.7,14.7],[-20.1,0],[-4.4,-9.8],[-11.1,-3.2]],"v":[[-40.2,-2.3],[-15.1,1.5],[56.9,1.6],[64.4,22.1],[63.2,120.2],[13.2,136.5],[-36.8,120.2],[-40.9,18.1]],"c":true}]},{"t":34,"s":[{"i":[[-10.8,-2.3],[-8.2,-0.4],[0,0],[3,-1.3],[4.4,-9.8],[24.175,0.094],[6.7,14.7],[-1.7,58.3]],"o":[[7.9,1.7],[0,0],[22.2,0],[0,0],[-6.669,14.144],[-20.1,-0.078],[-4.4,-9.8],[-11.1,-3.2]],"v":[[-40.2,-2.3],[-15.1,1.5],[56.9,1.6],[64.4,22.1],[63.044,119.606],[13.2,136.156],[-36.8,120.2],[-40.9,18.1]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"EXAMPLE ON","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256.462,259.5,0],"ix":2},"a":{"a":0,"k":[-0.038,1.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.1,0],[0,0],[0,-9.1],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[9,0],[0,0],[0,0],[0,0],[0,0],[0,-9.1]],"v":[[-1.6,-115.5],[-0.4,-115.5],[16,-99.1],[16,-89.5],[16,-89.5],[-18,-89.5],[-18,-99.1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.2]],"v":[[0,118.5],[25.6,96.7],[22.3,92.5],[-21.4,92.5],[-25.7,96.3]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,1.8],[0,0],[0,0],[36.4,8.6],[3.4,0],[5.9,-0.1],[0,-38.8],[0,0],[1.2,-1.3],[0,0],[0,0],[-11.3,0],[0,0],[8.1,7.9],[0,0]],"o":[[0,0],[0,0],[0,-38.6],[-6.7,-0.2],[-3,0],[-36.5,8.6],[0,0],[0,1.8],[0,0],[0,0],[-8,7.9],[0,0],[11.3,0],[0,0],[-1.1,-1.3]],"v":[[76.4,35.6],[76.4,-15.7],[76.4,-15.7],[14.3,-93.3],[-0.8,-93.5],[-14.2,-93.3],[-76.3,-15.7],[-76.3,35.6],[-78.1,40.4],[-92.8,57],[-92.8,57],[-81.5,78.5],[81.3,78.5],[92.7,57],[78.1,40.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Combined-Shape","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Bell","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[261.217,231.2,0],"to":[0,0,0],"ti":[0,0,0]},{"t":12,"s":[255.967,270.7,0]}],"ix":2},"a":{"a":0,"k":[-0.033,-25.3,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-11.475,14.325],[0,0],[0,0],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-66.9,-60.7],[52.121,57.296],[54.778,59.953],[70.15,79.575],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[-8.362,11.23],[0,0],[0,0],[3.762,-1.859],[8.142,-0.264],[0.62,12.856],[0.156,0.224],[1.314,3.134],[0.224,1.943],[0,0],[-0.582,7.711]],"o":[[0,0],[0,0],[0,0],[-19.321,9.547],[-26.964,1.125],[-0.005,-0.156],[-1.406,-14.295],[0.062,-2.373],[0,0],[-0.045,-4.946],[0,-7.124]],"v":[[-60.638,-49.681],[29.345,35.402],[55.841,63.676],[71.571,79.252],[-31.443,86.874],[-70.777,71.892],[-71,70.044],[-67.748,45.427],[-67.717,38.704],[-68.176,35.151],[-68.748,-3.168]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[-1.323,3.262],[0,0],[0,0],[6.275,-3.565],[14.005,-0.455],[0.542,0.356],[1.713,1.084],[2.26,5.391],[0.385,2.046],[0,0],[-1.001,13.264]],"o":[[0,0],[0,0],[0,0],[-4.624,2.627],[-40.891,-1.743],[0.542,-0.578],[-4.048,-2.564],[-0.758,-3.145],[0,0],[-0.077,-8.507],[0,-3.901]],"v":[[-57.609,-43.228],[22.617,23.841],[64.126,70.129],[61.225,80.722],[7.766,92.111],[-48.042,81.338],[-48.213,81.277],[-57.218,71.044],[-58.46,62.937],[-59.249,56.826],[-60.071,5.063]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[-0.309,0.762],[0,0],[0,0],[4.568,-5.804],[17.516,-1.439],[9.846,0.175],[5.202,1.836],[3.057,6.91],[0.521,1.988],[0,0],[-1.354,17]],"o":[[0,0],[0,0],[0,0],[-4.183,5.585],[-15.234,1.811],[-9.592,-0.227],[-5.947,-2.247],[-1.448,-3.573],[0,0],[-0.104,-10.903],[0,-0.911]],"v":[[-52.53,-28.79],[11.994,25.222],[67.477,74.382],[64.512,86.679],[25.234,99.127],[-10.469,99.989],[-34.862,95.528],[-48.272,82.948],[-50.586,74.249],[-51.653,66.417],[-52.765,18.153]],"c":true}]},{"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[4.095,-6.22],[20.07,-1.559],[12.041,0.281],[8.085,2.941],[3.171,6.676],[0.562,1.97],[0,0],[-1.461,18.138]],"o":[[0,0],[0,0],[0,0],[-4.095,6.221],[-5.657,0.44],[-12.041,-0.281],[-6.457,-2.348],[-1.741,-3.665],[0,0],[-0.112,-11.633],[0,0]],"v":[[-46.983,-24.891],[12.039,25.393],[71.061,75.677],[67.888,87.728],[34.61,102.118],[5.478,102.841],[-27.296,98.494],[-42.796,86.574],[-45.437,77.695],[-46.589,69.338],[-47.789,22.141]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[13.525,-18.6],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[10.58,-1.555]],"v":[[88.55,58.6],[73.795,40.25],[71.995,35.45],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-68.65,-58.275],[-25.568,-8.753],[-24.761,-7.935],[67.699,79.699],[80.6,78.975]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0.157,8.024],[0,0],[0,1.922],[0,0],[24.177,-0.77],[0,0],[9,0],[0,0],[5.709,0.272],[0,0],[-0.26,-17.504],[0,0],[0,0],[0,0],[-7.459,5.266]],"o":[[0,0],[-0.323,-1.991],[0,0],[1.096,-24.22],[0,0],[-9.573,2.118],[0,0],[-9.1,0],[0,0],[-6.6,1.142],[0,0],[0,0],[0,0],[0,0],[3.993,-2.819]],"v":[[71.843,56.59],[71.106,36.657],[70.583,30.009],[69.845,-21.987],[38.823,-52.309],[28.073,-50.661],[3.062,-46.678],[1.048,-46.86],[-26.209,-52.017],[-31.319,-53.002],[-58.24,-38.393],[-25.737,-8.451],[-22.131,-4.064],[59.51,80.628],[65.709,78.296]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0.094,4.576],[0,0],[0,1.828],[0,0],[20.355,-2.421],[0,0],[9,0],[0,0],[6.507,0.351],[0,0],[2.835,-13.717],[0,0],[0,0],[0,0],[-1.742,1.23]],"o":[[0,0],[-0.014,-2.094],[0,0],[-0.871,-19.045],[0,0],[-6.547,0.878],[0,0],[-9.1,0],[0,0],[-3.266,-0.12],[0,0],[0,0],[0,0],[0,0],[1.239,-8.208]],"v":[[69.031,57.556],[68.76,39.315],[68.408,33.605],[67.871,-20.767],[25.645,-36.641],[23.135,-36.246],[-0.875,-35.181],[-1.998,-35.415],[-22.891,-36.675],[-31.934,-38.285],[-52.647,-28.157],[-24.554,-1.976],[-21.081,1.4],[63.583,76.467],[67.733,76.517]],"c":true}]},{"t":12,"s":[{"i":[[0.075,3.525],[0,0],[0,1.8],[0,0],[24.75,0.638],[0,0],[9,0],[0,0],[6.75,0.375],[0,0],[-2.6,-5.6],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0.08,-2.125],[0,0],[1.85,-14.4],[0,0],[-5.625,0.5],[0,0],[-9.1,0],[0,0],[-2.25,-0.505],[0,0],[0,0],[0,0],[0,0],[0.4,-9.85]],"v":[[70.925,57.85],[70.795,40.125],[70.495,34.7],[71.4,-15.1],[22.75,-23.388],[22.75,-23.375],[0.35,-23.525],[0.15,-23.775],[-17.5,-24.5],[-23.5,-24.995],[-47.4,-25.4],[-21.443,-0.003],[-18.011,3.065],[67.387,75.199],[70.912,75.975]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":13,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Bottom Bell","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[0,137.7,0],"to":[0,0,0],"ti":[0,0,0]},{"t":12,"s":[12,91.7,0]}],"ix":2},"a":{"a":0,"k":[0,137.7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.1]],"v":[[-5.125,120.225],[20.6,99.05],[17.3,94.85],[-26.4,94.85],[-30.7,98.65]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[-19.183,0.659],[-2.93,11.67],[1.758,0],[29.45,0],[-0.296,-1.263]],"o":[[23.128,-0.795],[2.186,-3.703],[-15.091,0],[-1.319,0],[2.784,11.767]],"v":[[-2.487,124.469],[35.205,101.877],[29.62,99.793],[-34.409,99.793],[-40.709,103.488]],"c":true}]},{"t":12,"s":[{"i":[[-28.151,0],[-4.298,11.184],[2.579,0],[43.194,0],[-0.438,-1.209]],"o":[[27.506,0],[0.43,-1.305],[-22.134,0],[-1.934,0],[4.083,11.277]],"v":[[-0.461,137.5],[54.82,117.764],[47.729,113.85],[-46.18,113.85],[-55.42,117.392]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":10,"st":0,"bm":0}]},{"id":"comp_10","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[13.6,13.6,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":35,"st":0,"bm":0}]},{"id":"comp_11","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Line","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.67,"y":1},"o":{"x":0.33,"y":0},"t":6,"s":[1.687,-2.898,0],"to":[0,0,0],"ti":[0,0,0]},{"t":14,"s":[3.687,-6.898,0]}],"ix":2},"a":{"a":0,"k":[3.6,-7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":4,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.6,-111.5],[108.8,97.5]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.713,-119.559],[116.913,105.559]],"c":false}]},{"t":27,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.6,-111.5],[108.8,97.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":6,"s":[28]},{"t":14,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":6,"s":[71]},{"t":14,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-10","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":6,"op":35,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Head","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.6,-33.55,0],"ix":2},"a":{"a":0,"k":[-3.6,-33.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-25.4,0],[0,-25.4],[0,0],[6.9,-8],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[31.3,34.4],[-20.33,-17.23],[-49.6,-46.5],[-49.6,-71.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.2,2],[-25.4,0],[0,0],[0,0]],"v":[[-49.6,-15.4],[-40.702,-6.502],[-38.75,-4.55],[13.1,47.3],[-3.6,50.4],[-49.6,4.4],[-49.6,-15.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":13,"op":35,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arc L","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.31,"y":0},"t":14,"s":[-3.75,69.094,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":26,"s":[-3.75,88.094,0],"to":[0,0,0],"ti":[0,0,0]},{"t":34,"s":[-3.75,84.5,0]}],"ix":2},"a":{"a":0,"k":[-3.75,84.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.29,"y":0},"t":18,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.723],"y":[0.572]},"o":{"x":[0.4],"y":[0]},"t":5,"s":[15]},{"i":{"x":[0.695],"y":[0.627]},"o":{"x":[0.368],"y":[0.45]},"t":7,"s":[29]},{"i":{"x":[0.323],"y":[1]},"o":{"x":[0.222],"y":[0.388]},"t":8,"s":[37.868]},{"t":18,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.723],"y":[1.14]},"o":{"x":[0.4],"y":[0]},"t":5,"s":[12]},{"i":{"x":[0.695],"y":[0.945]},"o":{"x":[0.368],"y":[0.061]},"t":7,"s":[17.559]},{"i":{"x":[0.652],"y":[0.857]},"o":{"x":[0.357],"y":[0.122]},"t":8,"s":[9]},{"i":{"x":[0.426],"y":[1]},"o":{"x":[0.183],"y":[-2.717]},"t":10,"s":[0]},{"t":18,"s":[0]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":7,"op":35,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arc R","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[66.05,51.45,0],"ix":2},"a":{"a":0,"k":[66.05,51.45,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.29,"y":0},"t":18,"s":[{"i":[[0,0],[8.7,-12]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[64.7,50.5]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[8.7,-12]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[64.7,50.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":8,"s":[99]},{"t":18,"s":[0]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":11,"op":35,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Leg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252.45,380.6,0],"ix":2},"a":{"a":0,"k":[-3.55,124.6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.31,"y":0},"t":14,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.15,64],[-1.85,64],[9.55,75.4],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.55,75.4]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":26,"s":[{"i":[[-6.3,0],[0,0],[0,-2.846],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-2.846]],"v":[[-5.2,84.75],[-1.9,84.75],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true}]},{"t":34,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.2,78.5],[-1.9,78.5],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":10,"op":35,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Bell","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[259.064,256.028,0],"to":[0,0,0],"ti":[0,0,0]},{"t":14,"s":[253.564,241.028,0]}],"ix":2},"a":{"a":0,"k":[-1.88,-0.927,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[-16.045,13.245],[0,0],[0,0],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-61.4,-66.7],[44.371,41.071],[47.028,43.728],[73.9,79.64],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[-4.254,9.376],[0,0],[0,0],[0,0],[6.23,1.972],[-1.412,7.008],[0,0],[0,0],[0,1.507],[0.298,2.165],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-9.876,-1.385],[0,0],[0,0],[0.238,-1.694],[0,0],[-0.85,-6.164],[0.044,-6.601]],"v":[[-57.532,-45.068],[21.114,38.993],[23.375,41.218],[43.195,62.771],[-50.105,63.383],[-67.187,44.549],[-67.717,44.298],[-64.273,32.174],[-64.047,26.764],[-64.187,23.769],[-63.385,-11.302]],"c":true}]},{"t":14,"s":[{"i":[[-0.557,1.753],[0,0],[0,0],[0,0],[12.242,3.875],[4.463,6.051],[0,0],[0,0],[0,1.225],[0.586,4.254],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-8.598,-2.722],[0,0],[0,0],[-0.69,-2.075],[0,0],[-1.67,-12.113],[0.086,-1.777]],"v":[[-48.888,-16.333],[2.602,35.024],[4.48,36.832],[14.055,46.983],[-15.561,47.733],[-39.407,31.182],[-39.266,30.978],[-44.13,22.682],[-46.406,17.666],[-48.156,11.291],[-49.281,-8.366]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[12.143,-14.492],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[10.58,-1.555]],"v":[[88.55,58.6],[73.795,40.25],[71.995,35.45],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-63.338,-64.963],[-22.443,-19.878],[-21.636,-19.06],[71.262,79.637],[80.6,78.975]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[5.809,9.358],[-0.56,1.677],[0,1.8],[0,0],[30.628,11.768],[0,0],[10.446,-0.187],[0,0],[1.845,-5.655],[0,0],[2.161,-13.67],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-0.175,-1.881],[0,0],[0.112,-46.447],[0,0],[-2.26,-5.718],[0,0],[-11.578,-0.155],[0,0],[-27.545,10.149],[0,0],[0,0],[0,0],[0,0],[6.72,-2.318]],"v":[[62.53,35.324],[56.968,24.754],[57.164,18.109],[57.299,-17.272],[16.524,-101.941],[16.174,-105.284],[-4.079,-116.658],[-4.828,-116.69],[-26.225,-104.298],[-27.116,-100.217],[-56.572,-52.898],[-23.746,-18.806],[-23.05,-17.988],[50.468,61.936],[58.016,59.693]],"c":true}]},{"t":14,"s":[{"i":[[-2.182,4.07],[-1.1,3.295],[0,1.8],[0,0],[25.933,14.308],[0,0],[11.842,-0.367],[0,0],[3.626,-2.33],[0,0],[-2.875,-21.055],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0.815,-2.442],[0,0],[0.221,-54.605],[0,0],[-4.442,-2.455],[0,0],[-13.97,-0.305],[0,0],[-19.874,13.29],[0,0],[0,0],[0,0],[0,0],[2.995,-3.055]],"v":[[36.363,27.6],[40.655,19.625],[42.779,11.2],[43.21,-19.85],[21.372,-111.763],[20.684,-112.312],[-3.286,-118.838],[-3.6,-118.9],[-29.821,-110.375],[-31.571,-108.995],[-48.57,-47.15],[-22.056,-18.753],[-21.467,-17.935],[30.402,32.574],[31.31,33.225]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Bottom Bell","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[255.445,394.655,0],"ix":2},"a":{"a":0,"k":[0,137.7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":0,"s":[{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.1]],"v":[[1,119.605],[26.6,97.805],[23.3,93.605],[-20.4,93.605],[-24.7,97.405]],"c":true}]},{"t":10,"s":[{"i":[[-8.162,0],[0.625,15.53],[0.51,0.546],[4.907,-5.5],[0.14,-2.002]],"o":[[7.975,0],[0.125,-2.157],[-6.069,-6.5],[-0.373,0.418],[-1.164,16.646]],"v":[[-3.269,123.85],[10.181,105.515],[9.694,64.545],[-15.782,65.045],[-16.531,104.149]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":10,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"EXAMPLE ON","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-4.483,2.545,0],"ix":2},"a":{"a":0,"k":[-0.038,1.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.1,0],[0,0],[0,-9.1],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[9,0],[0,0],[0,0],[0,0],[0,0],[0,-9.1]],"v":[[-1.6,-115.5],[-0.4,-115.5],[16,-99.1],[16,-89.5],[16,-89.5],[-18,-89.5],[-18,-99.1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.2]],"v":[[0,118.5],[25.6,96.7],[22.3,92.5],[-21.4,92.5],[-25.7,96.3]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,1.8],[0,0],[0,0],[36.4,8.6],[3.4,0],[5.9,-0.1],[0,-38.8],[0,0],[1.2,-1.3],[0,0],[0,0],[-11.3,0],[0,0],[8.1,7.9],[0,0]],"o":[[0,0],[0,0],[0,-38.6],[-6.7,-0.2],[-3,0],[-36.5,8.6],[0,0],[0,1.8],[0,0],[0,0],[-8,7.9],[0,0],[11.3,0],[0,0],[-1.1,-1.3]],"v":[[76.4,35.6],[76.4,-15.7],[76.4,-15.7],[14.3,-93.3],[-0.8,-93.5],[-14.2,-93.3],[-76.3,-15.7],[-76.3,35.6],[-78.1,40.4],[-92.8,57],[-92.8,57],[-81.5,78.5],[81.3,78.5],[92.7,57],[78.1,40.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Combined-Shape","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":2,"st":0,"bm":0}]},{"id":"comp_12","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_13","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[13.6,13.6,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":29,"st":0,"bm":0}]},{"id":"comp_13","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"EXAMPLE ON","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.983,2.545,0],"ix":2},"a":{"a":0,"k":[-0.038,1.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.1,0],[0,0],[0,-9.1],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[9,0],[0,0],[0,0],[0,0],[0,0],[0,-9.1]],"v":[[-1.6,-115.5],[-0.4,-115.5],[16,-99.1],[16,-89.5],[16,-89.5],[-18,-89.5],[-18,-99.1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.2]],"v":[[0,118.5],[25.6,96.7],[22.3,92.5],[-21.4,92.5],[-25.7,96.3]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,1.8],[0,0],[0,0],[36.4,8.6],[3.4,0],[5.9,-0.1],[0,-38.8],[0,0],[1.2,-1.3],[0,0],[0,0],[-11.3,0],[0,0],[8.1,7.9],[0,0]],"o":[[0,0],[0,0],[0,-38.6],[-6.7,-0.2],[-3,0],[-36.5,8.6],[0,0],[0,1.8],[0,0],[0,0],[-8,7.9],[0,0],[11.3,0],[0,0],[-1.1,-1.3]],"v":[[76.4,35.6],[76.4,-15.7],[76.4,-15.7],[14.3,-93.3],[-0.8,-93.5],[-14.2,-93.3],[-76.3,-15.7],[-76.3,35.6],[-78.1,40.4],[-92.8,57],[-92.8,57],[-81.5,78.5],[81.3,78.5],[92.7,57],[78.1,40.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Combined-Shape","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Line Bell","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":0,"s":[-11.47,-25.859,0],"to":[0,0,0],"ti":[0,0,0]},{"t":17,"s":[5.03,-9.859,0]}],"ix":2},"a":{"a":0,"k":[-0.05,-2.95,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-98.152,-101.129],[98.052,95.229]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":0,"s":[0]},{"t":17,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":29,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Bottom Bell","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,137.7,0],"ix":2},"a":{"a":0,"k":[0,137.7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.1,0],[-2,12],[1.2,0],[20.1,0],[-0.2,-1.3]],"o":[[12.8,0],[0.2,-1.4],[-10.3,0],[-0.9,0],[1.9,12.1]],"v":[[-4.5,119.6],[21.1,97.8],[17.8,93.6],[-25.9,93.6],[-30.2,97.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":29,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Bell","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[260.562,232.132,0],"ix":2},"a":{"a":0,"k":[0.12,-24.927,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.72,0.72,0.72],"y":[1,1,1]},"o":{"x":[0.28,0.28,0.28],"y":[0,0,0]},"t":1,"s":[100,100,100]},{"i":{"x":[0.72,0.72,0.72],"y":[1,1,1]},"o":{"x":[0.28,0.28,0.28],"y":[0,0,0]},"t":12,"s":[93,93,100]},{"i":{"x":[0.72,0.72,0.72],"y":[1,1,1]},"o":{"x":[0.28,0.28,0.28],"y":[0,0,0]},"t":21,"s":[101,101,100]},{"t":28,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[-7.545,13.495],[0,0],[0,0],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-68.9,-57.2],[46.687,58.223],[49.57,61.102],[68.15,79.655],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[-5.872,11.598],[-1.72,-1.503],[-1.818,10.555],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[9.034,7.892],[6.962,6.261],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-73.235,-48.204],[-65.308,-41.244],[-37.924,-49.058],[74.965,79.428],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[-5.872,11.598],[-1.681,-1.546],[-1.818,10.555],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[11.181,10.285],[6.962,6.261],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-73.235,-48.204],[-35.586,-11.586],[-5.934,-19.545],[74.965,79.428],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[-5.036,10.649],[-2.391,-2.446],[-2.124,14.747],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[6.637,6.293],[10.443,9.392],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-73.817,-47.452],[-6.583,20.071],[22.942,7.689],[78.372,79.315],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[-4.2,9.7],[-3.062,-3.39],[-2.43,18.938],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[4.241,4.695],[13.924,12.522],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-74.4,-46.7],[19.467,48.272],[48.098,35.753],[81.779,79.202],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[-4.2,9.7],[-2.2,-2.106],[-1.62,12.626],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[9.752,9.336],[9.282,8.348],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-74.4,-46.7],[34.992,63.228],[69.333,53.948],[81.641,79.138],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]},{"t":10,"s":[{"i":[[-4.2,9.7],[0,0],[0,0],[0,0],[0,0],[-7.5,8],[0,0],[0,0],[0,1.8],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-11.2,0],[0,0],[0,0],[1.2,-1.3],[0,0],[0,0],[0,-11.6]],"v":[[-74.4,-46.7],[32.121,59.821],[34.778,62.478],[51.9,79.6],[-85.9,79.6],[-97.5,58.4],[-97.2,58.1],[-82.6,41.5],[-80.8,36.7],[-80.8,36.7],[-80.8,-14.6]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[9.346,-16.6],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[8,-1.6]],"v":[[89.05,58.35],[73.795,39.75],[71.995,34.95],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-69.215,-56.816],[-28.207,-15.716],[-27.434,-14.941],[66.835,79.54],[81.6,79.1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[2.875,-7.688],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[8,-1.6]],"v":[[89.05,58.35],[73.795,39.75],[71.995,34.95],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-55.392,-66.381],[-37.754,-49.074],[-39.423,-40.52],[73.962,79.404],[81.6,79.1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[2.875,-7.688],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[8,-1.6]],"v":[[89.05,58.35],[73.795,39.75],[71.995,34.95],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-55.392,-66.381],[-4.288,-18.099],[-3.284,-9.024],[73.962,79.404],[81.6,79.1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[2.047,-7.688],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[8,-1.6]],"v":[[89.05,58.35],[73.795,39.75],[71.995,34.95],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-56.464,-65.251],[-10.415,-18.43],[4.841,-14.706],[77.525,79.337],[81.6,79.1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[1.218,-7.689],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[8,-1.6]],"v":[[89.05,58.35],[73.795,39.75],[71.995,34.95],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-57.536,-64.121],[-15.752,-20.901],[36.667,21.906],[81.088,79.269],[81.6,79.1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[4.182,-9.084],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[8.86,-1.585]],"v":[[88.883,58.433],[73.795,39.917],[71.995,35.117],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-59.157,-64.714],[-11.573,-25.425],[-12.451,-25.128],[71.59,57.475],[81.267,79.058]],"c":true}]},{"t":10,"s":[{"i":[[6.6,6.5],[0,0],[0,1.8],[0,0],[35.493,9.136],[0,0],[9,0],[0,0],[0,-9.1],[0,0],[10.111,-11.873],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.2,-1.3],[0,0],[0,-37.993],[0,0],[0,-9.1],[0,0],[-9.1,0],[0,0],[-16.061,4.493],[0,0],[0,0],[0,0],[0,0],[10.58,-1.555]],"v":[[88.55,58.6],[73.795,40.25],[71.995,35.45],[71.9,-14.6],[11.5,-91.763],[11.5,-98],[-4.9,-114.4],[-6.1,-114.4],[-22.5,-98],[-22.5,-91.12],[-62.4,-65.9],[-19.568,-22.503],[-18.761,-21.685],[79.699,78.074],[80.6,78.975]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":29,"st":0,"bm":0}]},{"id":"comp_14","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 2","refId":"comp_15","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[30,30,0],"to":[0,0,0],"ti":[0,0,0]},{"t":10,"s":[28.282,29.857,0]}],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[13.6,13.6,100]},{"t":10,"s":[13.5,13.5,100]}],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":37,"st":0,"bm":0}]},{"id":"comp_15","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Head 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[0.613,-101.537,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[11.613,-50.537,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":26,"s":[11.613,-86.537,0],"to":[0,0,0],"ti":[0,0,0]},{"t":36,"s":[11.113,-83.037,0]}],"ix":2},"a":{"a":0,"k":[11.613,-84.537,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,-17.328],[25.612,0],[0,17.328],[-25.612,0]],"o":[[0,17.328],[-25.612,0],[0,-17.328],[25.612,0]],"v":[[54.039,-62.942],[7.664,-31.567],[-38.711,-62.942],[7.664,-94.317]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,-23.543],[25.081,0],[0,23.543],[-25.081,0]],"o":[[0,23.543],[-25.081,0],[0,-23.543],[25.081,0]],"v":[[55.47,-76.028],[10.057,-33.4],[-35.356,-76.028],[10.057,-118.656]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[0,-24.735],[24.735,0],[0,24.735],[-24.735,0]],"o":[[0,24.735],[-24.735,0],[0,-24.735],[24.735,0]],"v":[[56.4,-84.537],[11.613,-39.75],[-33.174,-84.537],[11.613,-129.324]],"c":true}]},{"t":25,"s":[{"i":[[0,-26.924],[26.924,0],[0,26.924],[-26.924,0]],"o":[[0,26.924],[-26.924,0],[0,-26.924],[26.924,0]],"v":[[60.363,-84.537],[11.613,-35.787],[-37.137,-84.537],[11.613,-133.287]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Hands 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.05,"y":0},"t":9,"s":[11.336,13.774,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.31,"y":0},"t":12,"s":[11.336,18.274,0],"to":[0,0,0],"ti":[0,0,0]},{"t":25,"s":[11.336,11.774,0]}],"ix":2},"a":{"a":0,"k":[11.336,10.774,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":7,"s":[{"i":[[0,0],[0.875,44.36],[0.012,11.61]],"o":[[0,0],[-0.348,-17.658],[-0.016,-14.955]],"v":[[-33.583,109.659],[-40.875,50.64],[-45.012,-17.11]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[-7.48,30.25],[-7.964,9.648]],"o":[[0,0],[2.73,-11.373],[7.228,-11.196]],"v":[[-57.163,97.688],[-57.996,36.651],[-42.036,0.102]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[-14.611,30.379],[-23.925,1.795]],"o":[[0,0],[7.389,-12.121],[13.171,-8.112]],"v":[[-77.526,99.758],[-81.889,29.906],[-41.075,4.99]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[0,0],[-27.718,19.589],[-10.136,-1.028]],"o":[[0,0],[21.782,-16.411],[19.114,-5.028]],"v":[[-107.888,77.829],[-93.782,16.161],[-42.114,8.877]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[0,0],[-27.325,4.127],[-14.975,-3.949]],"o":[[0,0],[20.334,-3.734],[35.444,0.066]],"v":[[-136.225,32.858],[-90.834,7.893],[-38.525,10.472]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[-27.129,-3.603],[-14.269,-4.157]],"o":[[0,0],[19.61,2.605],[43.609,2.613]],"v":[[-147.393,-5.627],[-89.61,-2.992],[-38.231,9.77]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[-38.825,-22.336],[-19.04,-2.789]],"o":[[0,0],[14.675,9.164],[62.76,8.586]],"v":[[-144.801,-73.381],[-91.175,-7.197],[-37.96,10.757]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[-46.458,-35.583],[-19.738,-3.567]],"o":[[0,0],[8.352,6.397],[79.039,14.286]],"v":[[-142.333,-130.341],[-88.062,-16.235],[-40.512,7.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":7,"s":[{"i":[[0,0],[0.583,25.777],[4.5,19.11]],"o":[[0,0],[-0.238,-10.518],[-18.41,-78.181]],"v":[[63,101.64],[63.167,54.973],[56,-16.61]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[2.455,25.149],[6.868,13.265]],"o":[[0,0],[-0.66,-9.745],[-29.265,-65.813]],"v":[[68.548,94.42],[70.368,48.723],[56.521,2.29]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[-11.495,10.995],[15.537,39.692],[11.504,1.535]],"o":[[14.034,-13.424],[-3.378,-8.551],[-47.075,-45.52]],"v":[[79.466,115.674],[91.463,38.058],[62.496,12.174]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[-14.54,10.097],[25.244,37.544],[12.466,1.965]],"o":[[15.872,-11.198],[-4.741,-7.952],[-56.007,-35.342]],"v":[[88.294,117.357],[93.089,33.781],[63.701,13.504]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[-16.063,9.648],[30.097,36.471],[11.946,0.457]],"o":[[16.791,-10.086],[-5.422,-7.653],[-60.473,-30.253]],"v":[[92.709,118.199],[93.903,31.642],[61.554,13.67]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[-5.509,3.309],[41.86,36.38],[11.653,0.923]],"o":[[5.759,-3.459],[-7.371,-6.796],[-73.243,-15.702]],"v":[[124.602,127.851],[94.405,26.111],[62.332,13.5]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":25,"s":[{"i":[[0,0],[48,36.333],[11.5,1.167]],"o":[[0,0],[-8.388,-6.35],[-79.91,-8.107]],"v":[[141.25,132.89],[94.667,23.223],[63.5,11.89]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[48,36.333],[11.5,1.167]],"o":[[0,0],[-8.388,-6.35],[-79.91,-8.107]],"v":[[140,128.89],[94.667,23.848],[63.5,11.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Body 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[266.676,398.378,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":23,"s":[266.676,387.378,0],"to":[0,0,0],"ti":[0,0,0]},{"t":34,"s":[266.676,392.378,0]}],"ix":2},"a":{"a":0,"k":[10.676,136.378,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.69,"y":1},"o":{"x":0.31,"y":0},"t":12,"s":[{"i":[[-12.288,0.098],[-12.498,-0.987],[0,0],[3.339,-1.222],[4.897,-9.213],[22.369,0],[7.456,13.82],[-1.892,54.808]],"o":[[8.847,-0.071],[35.724,2.82],[24.706,0],[0,0],[-7.456,13.82],[-22.369,0],[-4.897,-9.213],[-12.353,-3.008]],"v":[[-46.407,7.071],[-18.334,9.585],[61.794,9.679],[70.141,28.952],[68.805,121.176],[13.161,136.5],[-42.484,121.176],[-47.047,25.191]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.31,"y":0},"t":23,"s":[{"i":[[-10.8,-2.3],[-8.2,-0.4],[0,0],[3,-1.3],[4.4,-9.8],[20.1,0],[6.7,14.7],[-1.7,58.3]],"o":[[7.9,1.7],[0,0],[22.2,0],[0,0],[-6.7,14.7],[-20.1,0],[-4.4,-9.8],[-11.1,-3.2]],"v":[[-40.2,-2.3],[-15.1,1.5],[56.9,1.6],[64.4,22.1],[63.2,120.2],[13.2,136.5],[-36.8,120.2],[-40.9,18.1]],"c":true}]},{"t":34,"s":[{"i":[[-10.8,-2.3],[-8.2,-0.4],[0,0],[3,-1.3],[4.4,-9.8],[24.175,0.094],[6.7,14.7],[-1.7,58.3]],"o":[[7.9,1.7],[0,0],[22.2,0],[0,0],[-6.669,14.144],[-20.1,-0.078],[-4.4,-9.8],[-11.1,-3.2]],"v":[[-40.2,-2.3],[-15.1,1.5],[56.9,1.6],[64.4,22.1],[63.044,119.606],[13.2,136.156],[-36.8,120.2],[-40.9,18.1]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"EXAMPLE ON","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252.75,259.55,0],"ix":2},"a":{"a":0,"k":[0,3.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[45.3,0],[0,42]],"o":[[0,42],[-45.3,0],[0,0]],"v":[[82,8.4],[0,84.5],[-82,6.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-25.4,0],[0,0],[0,-25.4],[0,0],[25.4,0],[0,0],[0,25.4],[0,0]],"o":[[0,0],[25.4,0],[0,0],[0,25.4],[0,0],[-25.4,0],[0,0],[0,-25.4]],"v":[[0,-117.5],[0,-117.5],[46,-71.5],[46,4.5],[0,50.5],[0,50.5],[-46,4.5],[-46,-71.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-1.6,78.5],[1.7,78.5],[13.1,89.9],[13.1,113.2],[1.7,124.6],[-1.6,124.6],[-13,113.2],[-13,89.9]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Head Mic","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[-3.6,-33.55,0],"to":[0,0,0],"ti":[0,0,0]},{"t":12,"s":[9.4,60.45,0]}],"ix":2},"a":{"a":0,"k":[-3.6,-33.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[11.45,-8.15],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[25.8,40.525],[-28.33,-5.73],[-49.7,-35.75],[-49.6,-71.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[-25.393,-0.391],[0.18,-19.791],[-0.243,-7.895],[14.056,-6.795],[0,0],[0,0],[0,0]],"o":[[28.416,0.506],[0,0],[0.243,14.68],[0,0],[0,0],[0,0],[0.052,-15.482]],"v":[[-6.434,-101.102],[47.056,-73.018],[47.664,4.298],[29.68,40.735],[-22.557,-15.51],[-55.36,-50.751],[-55.066,-73.828]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[-25.388,-0.636],[-1.714,-14.258],[-0.395,-12.85],[18.974,-7.989],[0,0],[0,0],[0,0]],"o":[[30.309,0.824],[0,0],[0.395,16.737],[0,0],[0,0],[0,0],[2.421,-11.434]],"v":[[-4.713,-90.812],[49.978,-73.971],[50.966,4.171],[29.789,44.635],[-23.955,-14.43],[-58.974,-53.419],[-58.496,-75.289]],"c":true}]},{"t":12,"s":[{"i":[[-25.357,-0.966],[8.591,-7],[-0.599,-19.5],[30.67,-1.65],[0,0],[0,0],[0,0]],"o":[[32.818,1.25],[0,0],[0.599,19.5],[0,0],[0,0],[0,0],[7.976,-0.75]],"v":[[-7.528,-77],[56.909,-75.25],[58.407,4],[30.335,46.65],[-22.743,-12.98],[-60.7,-57],[-59.976,-81.5]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-11.6,9.325],[-25.4,0],[0,0],[0,0]],"v":[[-49.7,-36.15],[-27.202,-14.502],[-25.25,-12.55],[26.975,39.425],[-3.6,50.4],[-49.6,4.4],[-49.7,-31.65]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[6.435,0.16],[0,28.821],[0,0]],"o":[[0,0],[0,0],[0,0],[-13.044,10.194],[-29.138,-0.769],[0,0],[0,0]],"v":[[-55.579,-50.718],[-28.188,-26.309],[-26.057,-24.356],[32.281,39.246],[-10.39,49.691],[-55.329,4.4],[-55.38,-31.494]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[6.77,0.261],[0,30.968],[0,0]],"o":[[0,0],[0,0],[0,0],[-13.708,7.528],[-31.483,-1.252],[0,0],[0,0]],"v":[[-59.067,-54.691],[-31.67,-27.138],[-29.427,-25.186],[31.261,43.864],[-14.65,49.247],[-58.924,4.4],[-59.007,-41.593]],"c":true}]},{"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[7.214,0.396],[0,33.85],[0,0]],"o":[[0,0],[0,0],[0,0],[-14.586,3.95],[-34.597,-1.9],[0,0],[0,0]],"v":[[-60.625,-60.025],[-33.246,-28.252],[-30.856,-26.3],[32.633,46.55],[-17.287,48.65],[-60.625,4.4],[-60.75,-55.15]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":13,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Arc L","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.75,84.5,0],"ix":2},"a":{"a":0,"k":[-3.75,84.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":2,"s":[{"i":[[0,0],[17.605,8.684],[-3.033,28.67]],"o":[[-19.95,7.814],[-28.895,-17.316],[0,0]],"v":[[24.45,79.436],[-39.105,77.316],[-76.362,0.644]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[11.789,14.347],[-5.217,19.073]],"o":[[-50.375,15.159],[-15.78,-19.203],[0,0]],"v":[[26.125,87.591],[-58.72,68.703],[-69.783,-3.573]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[3.96,23.737],[-17.216,17.641]],"o":[[-21.241,-5.148],[-3.54,-27.263],[0,0]],"v":[[-26.759,91.648],[-66.96,42.763],[-43.784,-26.641]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0,0],[0.701,27.677],[-23.215,14.71]],"o":[[-17.607,-9.204],[-0.405,-15.984],[0,0]],"v":[[-32.893,81.704],[-69.201,29.323],[-41.785,-18.71]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[-6.372,14.388],[-16.86,4.436]],"o":[[-9.639,-11.784],[6.608,-14.922],[0,0]],"v":[[-74.929,75.894],[-84.108,31.922],[-41.89,3.314]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[-14.453,13.82],[-10.072,-1.911]],"o":[[-3.391,-12.713],[16.367,-15.651],[0,0]],"v":[[-102.109,72.713],[-93.047,27.18],[-41.962,18.507]],"c":false}]},{"t":12,"s":[{"i":[[0,0],[-10.081,5.804],[-6.5,-5.25]],"o":[[-1.25,-14.5],[24.75,-14.25],[0,0]],"v":[[-121.75,68.75],[-97.75,28.5],[-42,26.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":13,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Arc R","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[66.05,51.45,0],"ix":2},"a":{"a":0,"k":[66.05,51.45,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0,0],[42.3,-15.5]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[28.45,78.125]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":2,"s":[{"i":[[0,0],[45.259,-17.574]],"o":[[5.569,19.742],[0,0]],"v":[[71.436,-1.265],[27.374,78.492]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[47.39,-19.067]],"o":[[9.578,22.724],[0,0]],"v":[[66.422,-8.224],[29.61,86.067]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[43.341,-23.274]],"o":[[42.63,43.092],[0,0]],"v":[[43.37,-29.592],[33.159,90.274]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0,0],[32.542,-17.732]],"o":[[46.682,32.959],[0,0]],"v":[[44.318,-21.959],[47.958,77.232]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[29.55,-17.51]],"o":[[48.487,23.807],[0,0]],"v":[[50.036,1.981],[67.878,99.974]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[0,0],[28.054,-17.399]],"o":[[49.39,19.231],[0,0]],"v":[[56.395,12.201],[71.838,111.344]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[27.199,-17.335]],"o":[[49.907,16.614],[0,0]],"v":[[57.245,18.726],[77.588,118.775]],"c":false}]},{"t":12,"s":[{"i":[[0,0],[26.05,-17.25]],"o":[[47.35,10.35],[0,0]],"v":[[62.15,25.9],[83.95,128.75]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Leg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252.45,380.6,0],"ix":2},"a":{"a":0,"k":[-3.55,124.6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.2,78.5],[-1.9,78.5],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[-10.717,-0.585],[0,0],[-5.941,-0.906],[0.206,-8.157],[11.865,-1.977],[0,0],[1.529,7.318],[0,0]],"o":[[0,0],[12.64,0.23],[0,0],[-0.717,13.324],[0,0],[-9.832,-0.809],[-1.086,-1.566],[7.288,1.01]],"v":[[-6.991,83.123],[-1.449,83.426],[26.156,78.756],[29.671,97.051],[10.094,121.234],[-4.602,122.184],[-26.436,108.079],[-29.519,79.278]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[-15.856,0],[0,0],[-3.721,-3.379],[3.175,-9.561],[10.154,-0.123],[0,0],[3.074,9.411],[0,0]],"o":[[0,0],[17.039,-0.353],[0,0],[-4.368,11.421],[0,0],[-13.978,-0.72],[-2.523,-3.997],[4.562,-2.465]],"v":[[-1.547,83.311],[6.603,83.311],[48.503,77.629],[40.118,101.079],[14.346,125.123],[-0.309,126.215],[-28.324,109.339],[-40.364,80.189]],"c":true}]},{"t":12,"s":[{"i":[[-24.292,0],[0,0],[0,-6.3],[8.795,-7.101],[15.905,-0.35],[0,0],[7.818,10.05],[0,0]],"o":[[0,0],[24.292,0],[0,0],[-9.351,7.55],[0,0],[-20.755,-1.1],[-4.75,-6.106],[0,-6.3]],"v":[[1.971,106.75],[14.403,106.75],[66.25,108.9],[57.149,125.2],[14.987,135.85],[2.263,135.85],[-43.318,122.45],[-49,110.15]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":10,"st":0,"bm":0}]},{"id":"comp_16","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_17","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[30,30,0],"to":[0,0,0],"ti":[0,0,0]},{"t":10,"s":[28.282,29.857,0]}],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[13.6,13.6,100]},{"t":10,"s":[13.5,13.5,100]}],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":37,"st":0,"bm":0}]},{"id":"comp_17","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Line","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[3.687,-6.898,0],"to":[0,0,0],"ti":[0,0,0]},{"t":8,"s":[-3.313,3.102,0]}],"ix":2},"a":{"a":0,"k":[3.6,-7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.6,-111.5],[108.8,97.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":0,"s":[0]},{"t":7,"s":[31]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":0,"s":[100]},{"t":7,"s":[63]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-10","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":9,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Head Mic","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[-3.6,-33.55,0],"to":[0,0,0],"ti":[0,0,0]},{"t":12,"s":[9.4,60.45,0]}],"ix":2},"a":{"a":0,"k":[-3.6,-33.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[6.9,-8],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[31.3,34.4],[-20.33,-17.23],[-49.6,-46.5],[-49.6,-71.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[-25.393,-0.391],[0.18,-19.791],[-0.243,-7.895],[14.056,-6.795],[0,0],[0,0],[0,0]],"o":[[28.416,0.506],[0,0],[0.243,14.68],[0,0],[0,0],[0,0],[0.052,-15.482]],"v":[[-6.434,-101.102],[47.056,-73.018],[47.664,4.298],[29.68,40.735],[-22.557,-15.51],[-55.36,-50.751],[-55.066,-73.828]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[-25.388,-0.636],[-1.714,-14.258],[-0.395,-12.85],[18.974,-7.989],[0,0],[0,0],[0,0]],"o":[[30.309,0.824],[0,0],[0.395,16.737],[0,0],[0,0],[0,0],[2.421,-11.434]],"v":[[-4.713,-90.812],[49.978,-73.971],[50.966,4.171],[29.789,44.635],[-23.955,-14.43],[-58.974,-53.419],[-58.496,-75.289]],"c":true}]},{"t":12,"s":[{"i":[[-25.306,-0.966],[8.574,-7],[-0.598,-19.5],[30.609,-1.65],[0,0],[0,0],[0,0]],"o":[[32.753,1.25],[0,0],[0.598,19.5],[0,0],[0,0],[0,0],[5.227,-2.25]],"v":[[-7.633,-77],[56.676,-75.25],[58.171,4],[29.904,46.4],[-22.818,-12.98],[-60.7,-57],[-59.227,-81]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.2,2],[-25.4,0],[0,0],[0,0]],"v":[[-49.6,-15.4],[-40.702,-6.502],[-38.75,-4.55],[13.1,47.3],[-3.6,50.4],[-49.6,4.4],[-49.6,-15.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[6.435,0.16],[0,28.821],[0,0]],"o":[[0,0],[0,0],[0,0],[-13.044,10.194],[-29.138,-0.769],[0,0],[0,0]],"v":[[-55.579,-50.718],[-28.188,-26.309],[-26.057,-24.356],[32.281,39.246],[-10.39,49.691],[-55.329,4.4],[-55.38,-31.494]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[6.77,0.261],[0,30.968],[0,0]],"o":[[0,0],[0,0],[0,0],[-13.708,7.528],[-31.483,-1.252],[0,0],[0,0]],"v":[[-59.067,-54.691],[-31.67,-27.138],[-29.427,-25.186],[31.261,43.864],[-14.65,49.247],[-58.924,4.4],[-59.007,-41.593]],"c":true}]},{"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[7.199,0.396],[0,33.85],[0,0]],"o":[[0,0],[0,0],[0,0],[-14.557,3.95],[-34.528,-1.9],[0,0],[0,0]],"v":[[-60.625,-60.025],[-33.301,-28.252],[-30.915,-26.3],[32.198,46.3],[-17.623,48.4],[-60.625,4.4],[-60.75,-55.15]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arc L","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.75,84.5,0],"ix":2},"a":{"a":0,"k":[-3.75,84.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":2,"s":[{"i":[[0,0],[17.605,8.684],[-3.033,28.67]],"o":[[-19.95,7.814],[-28.895,-17.316],[0,0]],"v":[[24.45,79.436],[-39.105,77.316],[-76.362,0.644]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[11.789,14.347],[-5.217,19.073]],"o":[[-50.375,15.159],[-15.78,-19.203],[0,0]],"v":[[26.125,87.591],[-58.72,68.703],[-69.783,-3.573]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[3.96,23.737],[-17.216,17.641]],"o":[[-21.241,-5.148],[-3.54,-27.263],[0,0]],"v":[[-26.759,91.648],[-66.96,42.763],[-43.784,-26.641]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0,0],[0.701,27.677],[-23.215,14.71]],"o":[[-17.607,-9.204],[-0.405,-15.984],[0,0]],"v":[[-32.893,81.704],[-69.201,29.323],[-41.785,-18.71]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[-6.372,14.388],[-16.86,4.436]],"o":[[-9.639,-11.784],[6.608,-14.922],[0,0]],"v":[[-74.929,75.894],[-84.108,31.922],[-41.89,3.314]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[-14.453,13.82],[-10.072,-1.911]],"o":[[-3.391,-12.713],[16.367,-15.651],[0,0]],"v":[[-102.109,72.713],[-93.047,27.18],[-41.962,18.507]],"c":false}]},{"t":12,"s":[{"i":[[0,0],[-10.081,5.804],[-6.5,-5.25]],"o":[[-1.25,-14.5],[24.75,-14.25],[0,0]],"v":[[-121.75,68.75],[-97.75,28.5],[-42,26.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arc R","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[66.05,51.45,0],"ix":2},"a":{"a":0,"k":[66.05,51.45,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0,0],[8.7,-12]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[64.7,50.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[16.64,-12.817]],"o":[[15.078,25.724],[0,0]],"v":[[66.422,-8.224],[58.36,66.317]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[38.841,-19.274]],"o":[[42.63,43.092],[0,0]],"v":[[43.37,-29.592],[35.659,89.274]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0,0],[32.542,-17.732]],"o":[[46.682,32.959],[0,0]],"v":[[44.318,-21.959],[47.958,77.232]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[29.55,-17.51]],"o":[[48.487,23.807],[0,0]],"v":[[50.036,1.981],[67.878,99.974]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[0,0],[28.054,-17.399]],"o":[[49.39,19.231],[0,0]],"v":[[56.395,12.201],[71.838,111.344]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[27.199,-17.335]],"o":[[49.907,16.614],[0,0]],"v":[[57.245,18.726],[77.588,118.775]],"c":false}]},{"t":12,"s":[{"i":[[0,0],[26.05,-17.25]],"o":[[47.35,10.35],[0,0]],"v":[[62.15,25.9],[83.95,128.75]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Leg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252.45,380.6,0],"ix":2},"a":{"a":0,"k":[-3.55,124.6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.2,78.5],[-1.9,78.5],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[-10.717,-0.585],[0,0],[-5.941,-0.906],[0.206,-8.157],[11.865,-1.977],[0,0],[1.529,7.318],[0,0]],"o":[[0,0],[12.64,0.23],[0,0],[-0.717,13.324],[0,0],[-9.832,-0.809],[-1.086,-1.566],[7.288,1.01]],"v":[[-6.991,83.123],[-1.449,83.426],[26.156,78.756],[29.671,97.051],[10.094,121.234],[-4.602,122.184],[-26.436,108.079],[-29.519,79.278]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[-15.856,0],[0,0],[-3.721,-3.379],[3.175,-9.561],[10.154,-0.123],[0,0],[3.074,9.411],[0,0]],"o":[[0,0],[17.039,-0.353],[0,0],[-4.368,11.421],[0,0],[-13.978,-0.72],[-2.523,-3.997],[4.562,-2.465]],"v":[[-1.547,83.311],[6.603,83.311],[48.503,77.629],[40.118,101.079],[14.346,125.123],[-0.309,126.215],[-28.324,109.339],[-40.364,80.189]],"c":true}]},{"t":12,"s":[{"i":[[-24.292,0],[0,0],[0,-6.3],[8.795,-7.101],[15.905,-0.35],[0,0],[7.818,10.05],[0,0]],"o":[[0,0],[24.292,0],[0,0],[-9.351,7.55],[0,0],[-20.755,-1.1],[-4.75,-6.106],[0,-6.3]],"v":[[1.971,106.75],[14.403,106.75],[66.25,108.9],[57.149,125.2],[14.987,135.85],[2.263,135.85],[-43.318,122.45],[-49,110.15]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":10,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Head 2","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[0.613,-101.537,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[11.613,-50.537,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":26,"s":[11.613,-86.537,0],"to":[0,0,0],"ti":[0,0,0]},{"t":36,"s":[11.113,-83.037,0]}],"ix":2},"a":{"a":0,"k":[11.613,-84.537,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,-17.328],[25.612,0],[0,17.328],[-25.612,0]],"o":[[0,17.328],[-25.612,0],[0,-17.328],[25.612,0]],"v":[[54.039,-62.942],[7.664,-31.567],[-38.711,-62.942],[7.664,-94.317]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,-23.543],[25.081,0],[0,23.543],[-25.081,0]],"o":[[0,23.543],[-25.081,0],[0,-23.543],[25.081,0]],"v":[[55.47,-76.028],[10.057,-33.4],[-35.356,-76.028],[10.057,-118.656]],"c":true}]},{"i":{"x":0.39,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[0,-24.735],[24.735,0],[0,24.735],[-24.735,0]],"o":[[0,24.735],[-24.735,0],[0,-24.735],[24.735,0]],"v":[[56.4,-84.537],[11.613,-39.75],[-33.174,-84.537],[11.613,-129.324]],"c":true}]},{"t":25,"s":[{"i":[[0,-26.924],[26.924,0],[0,26.924],[-26.924,0]],"o":[[0,26.924],[-26.924,0],[0,-26.924],[26.924,0]],"v":[[60.363,-84.537],[11.613,-35.787],[-37.137,-84.537],[11.613,-133.287]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":37,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Hands 2","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.05,"y":0},"t":9,"s":[11.336,13.774,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.31,"y":0},"t":12,"s":[11.336,18.274,0],"to":[0,0,0],"ti":[0,0,0]},{"t":25,"s":[11.336,11.774,0]}],"ix":2},"a":{"a":0,"k":[11.336,10.774,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":7,"s":[{"i":[[0,0],[0.875,44.36],[0.012,11.61]],"o":[[0,0],[-0.348,-17.658],[-0.016,-14.955]],"v":[[-33.583,109.659],[-40.875,50.64],[-45.012,-17.11]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[-7.48,30.25],[-7.964,9.648]],"o":[[0,0],[2.73,-11.373],[7.228,-11.196]],"v":[[-57.163,97.688],[-57.996,36.651],[-42.036,0.102]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[-14.611,30.379],[-23.925,1.795]],"o":[[0,0],[7.389,-12.121],[13.171,-8.112]],"v":[[-77.526,99.758],[-81.889,29.906],[-41.075,4.99]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[0,0],[-27.718,19.589],[-10.136,-1.028]],"o":[[0,0],[21.782,-16.411],[19.114,-5.028]],"v":[[-107.888,77.829],[-93.782,16.161],[-42.114,8.877]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[0,0],[-27.325,4.127],[-14.975,-3.949]],"o":[[0,0],[20.334,-3.734],[35.444,0.066]],"v":[[-136.225,32.858],[-90.834,7.893],[-38.525,10.472]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[-27.129,-3.603],[-14.269,-4.157]],"o":[[0,0],[19.61,2.605],[43.609,2.613]],"v":[[-147.393,-5.627],[-89.61,-2.992],[-38.231,9.77]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[-38.825,-22.336],[-19.04,-2.789]],"o":[[0,0],[14.675,9.164],[62.76,8.586]],"v":[[-144.801,-73.381],[-91.175,-7.197],[-37.96,10.757]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[-46.458,-35.583],[-19.738,-3.567]],"o":[[0,0],[8.352,6.397],[79.039,14.286]],"v":[[-142.333,-130.341],[-88.062,-16.235],[-40.512,7.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":7,"s":[{"i":[[0,0],[0.583,25.777],[4.5,19.11]],"o":[[0,0],[-0.238,-10.518],[-18.41,-78.181]],"v":[[63,101.64],[63.167,54.973],[56,-16.61]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[2.455,25.149],[6.868,13.265]],"o":[[0,0],[-0.66,-9.745],[-29.265,-65.813]],"v":[[68.548,94.42],[70.368,48.723],[56.521,2.29]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[-11.495,10.995],[15.537,39.692],[11.504,1.535]],"o":[[14.034,-13.424],[-3.378,-8.551],[-47.075,-45.52]],"v":[[79.466,115.674],[91.463,38.058],[62.496,12.174]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[-14.54,10.097],[25.244,37.544],[12.466,1.965]],"o":[[15.872,-11.198],[-4.741,-7.952],[-56.007,-35.342]],"v":[[88.294,117.357],[93.089,33.781],[63.701,13.504]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[-16.063,9.648],[30.097,36.471],[11.946,0.457]],"o":[[16.791,-10.086],[-5.422,-7.653],[-60.473,-30.253]],"v":[[92.709,118.199],[93.903,31.642],[61.554,13.67]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[-5.509,3.309],[41.86,36.38],[11.653,0.923]],"o":[[5.759,-3.459],[-7.371,-6.796],[-73.243,-15.702]],"v":[[124.602,127.851],[94.405,26.111],[62.332,13.5]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":25,"s":[{"i":[[0,0],[48,36.333],[11.5,1.167]],"o":[[0,0],[-8.388,-6.35],[-79.91,-8.107]],"v":[[141.25,132.89],[94.667,23.223],[63.5,11.89]],"c":false}]},{"t":28,"s":[{"i":[[0,0],[48,36.333],[11.5,1.167]],"o":[[0,0],[-8.388,-6.35],[-79.91,-8.107]],"v":[[140,128.89],[94.667,23.848],[63.5,11.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":37,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Body 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[266.676,398.378,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":23,"s":[266.676,387.378,0],"to":[0,0,0],"ti":[0,0,0]},{"t":34,"s":[266.676,392.378,0]}],"ix":2},"a":{"a":0,"k":[10.676,136.378,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.69,"y":1},"o":{"x":0.31,"y":0},"t":12,"s":[{"i":[[-12.288,0.098],[-12.498,-0.987],[0,0],[3.339,-1.222],[4.897,-9.213],[22.369,0],[7.456,13.82],[-1.892,54.808]],"o":[[8.847,-0.071],[35.724,2.82],[24.706,0],[0,0],[-7.456,13.82],[-22.369,0],[-4.897,-9.213],[-12.353,-3.008]],"v":[[-46.407,7.071],[-18.334,9.585],[61.794,9.679],[70.141,28.952],[68.805,121.176],[13.161,136.5],[-42.484,121.176],[-47.047,25.191]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.31,"y":0},"t":23,"s":[{"i":[[-10.8,-2.3],[-8.2,-0.4],[0,0],[3,-1.3],[4.4,-9.8],[20.1,0],[6.7,14.7],[-1.7,58.3]],"o":[[7.9,1.7],[0,0],[22.2,0],[0,0],[-6.7,14.7],[-20.1,0],[-4.4,-9.8],[-11.1,-3.2]],"v":[[-40.2,-2.3],[-15.1,1.5],[56.9,1.6],[64.4,22.1],[63.2,120.2],[13.2,136.5],[-36.8,120.2],[-40.9,18.1]],"c":true}]},{"t":34,"s":[{"i":[[-10.8,-2.3],[-8.2,-0.4],[0,0],[3,-1.3],[4.4,-9.8],[24.175,0.094],[6.7,14.7],[-1.7,58.3]],"o":[[7.9,1.7],[0,0],[22.2,0],[0,0],[-6.669,14.144],[-20.1,-0.078],[-4.4,-9.8],[-11.1,-3.2]],"v":[[-40.2,-2.3],[-15.1,1.5],[56.9,1.6],[64.4,22.1],[63.044,119.606],[13.2,136.156],[-36.8,120.2],[-40.9,18.1]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":37,"st":0,"bm":0}]},{"id":"comp_18","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_19","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[13.6,13.6,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":30,"st":0,"bm":0}]},{"id":"comp_19","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.042,238.57,0],"ix":2},"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.72,0.72,0.72],"y":[1,1,1]},"o":{"x":[0.28,0.28,0.28],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.72,0.72,0.72],"y":[1,1,1]},"o":{"x":[0.28,0.28,0.28],"y":[0,0,0]},"t":11,"s":[93,93,100]},{"i":{"x":[0.72,0.72,0.72],"y":[1,1,1]},"o":{"x":[0.28,0.28,0.28],"y":[0,0,0]},"t":21,"s":[101,101,100]},{"t":29,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Line","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":0,"s":[-13.538,-23.613,0],"to":[0,0,0],"ti":[0,0,0]},{"t":17,"s":[3.687,-6.898,0]}],"ix":2},"a":{"a":0,"k":[3.6,-7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.6,-111.5],[108.8,97.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":0,"s":[0]},{"t":17,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-10","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":30,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Head","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.6,-33.55,0],"ix":2},"a":{"a":0,"k":[-3.6,-33.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[15.481,-9.962],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[23.519,42.712],[-23.209,-2.257],[-49.7,-27.75],[-49.6,-71.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[6.9,-8],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[31.3,34.4],[-10.034,-21.084],[-49.6,-46.5],[-49.6,-71.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[6.9,-8],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[31.3,34.4],[19.623,9.37],[-49.6,-46.5],[-49.6,-71.5]],"c":true}]},{"t":8,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[6.9,-8],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[31.3,34.4],[-20.33,-17.23],[-49.6,-46.5],[-49.6,-71.5]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-12.35,7.7],[-25.4,0],[0,0],[0,0]],"v":[[-49.7,-29.15],[-39.262,-18.975],[-36.972,-16.742],[23.85,42.55],[-3.6,50.4],[-49.6,4.4],[-49.7,-29.15]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0,0],[-3.331,-2.789],[4.414,24.475],[0,0],[12.582,-0.112],[0,25.4],[0,0]],"o":[[0,0],[4.215,3.528],[21.749,15.62],[-9.968,12.883],[-25.399,0.226],[0,0],[0,0]],"v":[[-49.6,-15.4],[-38.553,-4.468],[-12.248,-24.48],[31.491,33.902],[-3.6,50.4],[-49.6,4.4],[-49.6,-15.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[-1.647,-1.416],[3.578,20.948],[0,0],[13.582,-0.261],[0,25.4],[0,0]],"o":[[0,0],[7.932,6.822],[10.875,7.81],[-10.683,10.613],[-25.395,0.487],[0,0],[0,0]],"v":[[-49.6,-15.4],[-6.153,27.653],[21.197,9.349],[31.475,35.139],[-3.6,50.4],[-49.6,4.4],[-49.6,-15.4]],"c":true}]},{"t":8,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.2,2],[-25.4,0],[0,0],[0,0]],"v":[[-49.6,-15.4],[-40.702,-6.502],[-38.75,-4.55],[13.1,47.3],[-3.6,50.4],[-49.6,4.4],[-49.6,-15.4]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arc L","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.75,84.5,0],"ix":2},"a":{"a":0,"k":[-3.75,84.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Arc R","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[66.05,51.45,0],"ix":2},"a":{"a":0,"k":[66.05,51.45,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[0,0],[34.576,-19.595]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[38.027,74.567]],"c":false}]},{"t":9,"s":[{"i":[[0,0],[8.7,-12]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[64.7,50.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Leg","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[48.408,192.03,0],"ix":2},"a":{"a":0,"k":[-3.55,124.6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.2,78.5],[-1.9,78.5],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"EXAMPLE ON","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[48.708,70.98,0],"ix":2},"a":{"a":0,"k":[0,3.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[45.3,0],[0,42]],"o":[[0,42],[-45.3,0],[0,0]],"v":[[82,8.4],[0,84.5],[-82,6.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20.888,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-25.4,0],[0,0],[0,-25.4],[0,0],[25.4,0],[0,0],[0,25.4],[0,0]],"o":[[0,0],[25.4,0],[0,0],[0,25.4],[0,0],[-25.4,0],[0,0],[0,-25.4]],"v":[[0,-117.5],[0,-117.5],[46,-71.5],[46,4.5],[0,50.5],[0,50.5],[-46,4.5],[-46,-71.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-1.6,78.5],[1.7,78.5],[13.1,89.9],[13.1,113.2],[1.7,124.6],[-1.6,124.6],[-13,113.2],[-13,89.9]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":5,"st":0,"bm":0}]},{"id":"comp_20","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_21","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[13.6,13.6,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":33,"st":0,"bm":0}]},{"id":"comp_21","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.062,238.57,0],"ix":2},"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":12,"s":[93,93,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":22,"s":[101,101,100]},{"t":32,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":0,"op":33,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Line","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":2,"s":[3.687,-6.898,0],"to":[0,0,0],"ti":[0,0,0]},{"t":23,"s":[12.601,2.016,0]}],"ix":2},"a":{"a":0,"k":[3.6,-7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.6,-111.5],[108.8,97.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":2,"s":[0]},{"t":23,"s":[100]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-10","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":21,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Head","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.6,-33.55,0],"ix":2},"a":{"a":0,"k":[-3.6,-33.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[6.9,-8],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[31.3,34.4],[-20.33,-17.23],[-49.6,-46.5],[-49.6,-71.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[5.665,-6.576],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[32.133,31.549],[-27.809,-30.43],[-49.62,-42.75],[-49.6,-71.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[5.665,-6.576],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[32.133,31.549],[-4.565,-6.652],[-49.62,-42.75],[-49.6,-71.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[5.665,-6.576],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[32.133,31.549],[17.977,14.816],[-49.62,-42.75],[-49.6,-71.5]],"c":true}]},{"t":12,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[15.481,-9.962],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[23.519,42.712],[-23.209,-2.257],[-49.7,-27.75],[-49.6,-71.5]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.2,2],[-25.4,0],[0,0],[0,0]],"v":[[-49.6,-15.4],[-40.702,-6.502],[-38.75,-4.55],[13.1,47.3],[-3.6,50.4],[-49.6,4.4],[-49.6,-15.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[0,0],[-11.683,-16.357],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[4.734,6.628],[-6.63,3.14],[-25.4,0],[0,0],[0,0]],"v":[[-49.575,-44.964],[-29.795,-33.421],[-38.394,-6.988],[15.25,46.35],[-3.6,50.4],[-49.6,4.4],[-49.575,-44.167]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[0,0],[-11.683,-16.357],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[4.734,6.628],[-6.63,3.14],[-25.4,0],[0,0],[0,0]],"v":[[-49.575,-44.964],[-6.551,-9.643],[-15.151,16.79],[15.25,46.35],[-3.6,50.4],[-49.6,4.4],[-49.575,-44.167]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[0,0],[0,0],[-11.683,-16.357],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[4.734,6.628],[-6.63,3.14],[-25.4,0],[0,0],[0,0]],"v":[[-49.575,-44.964],[15.99,11.825],[7.391,38.258],[15.25,46.35],[-3.6,50.4],[-49.6,4.4],[-49.575,-44.167]],"c":true}]},{"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-12.35,7.7],[-25.4,0],[0,0],[0,0]],"v":[[-49.7,-29.15],[-39.262,-18.975],[-36.972,-16.742],[23.85,42.55],[-3.6,50.4],[-49.6,4.4],[-49.7,-29.15]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":33,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arc L","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.75,84.5,0],"ix":2},"a":{"a":0,"k":[-3.75,84.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":33,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Arc R","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[66.05,51.45,0],"ix":2},"a":{"a":0,"k":[66.05,51.45,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[0,0],[8.7,-12]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[64.7,50.5]],"c":false}]},{"t":14,"s":[{"i":[[0,0],[36.503,-16.928]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[34.73,75.676]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":33,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Leg","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[48.408,192.03,0],"ix":2},"a":{"a":0,"k":[-3.55,124.6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.2,78.5],[-1.9,78.5],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":33,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"EXAMPLE ON","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[48.708,70.98,0],"ix":2},"a":{"a":0,"k":[0,3.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[45.3,0],[0,42]],"o":[[0,42],[-45.3,0],[0,0]],"v":[[82,8.4],[0,84.5],[-82,6.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20.888,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-25.4,0],[0,0],[0,-25.4],[0,0],[25.4,0],[0,0],[0,25.4],[0,0]],"o":[[0,0],[25.4,0],[0,0],[0,25.4],[0,0],[-25.4,0],[0,0],[0,-25.4]],"v":[[0,-117.5],[0,-117.5],[46,-71.5],[46,4.5],[0,50.5],[0,50.5],[-46,4.5],[-46,-71.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-1.6,78.5],[1.7,78.5],[13.1,89.9],[13.1,113.2],[1.7,124.6],[-1.6,124.6],[-13,113.2],[-13,89.9]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":33,"st":0,"bm":0}]},{"id":"comp_22","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 2","refId":"comp_23","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[28.282,29.857,0],"to":[0,0,0],"ti":[0,0,0]},{"t":10,"s":[30,30,0]}],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[13.5,13.5,100]},{"t":10,"s":[13.6,13.6,100]}],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":36,"st":0,"bm":0}]},{"id":"comp_23","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Head 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[11.613,-83.537,0],"to":[0,0,0],"ti":[0,0,0]},{"t":14,"s":[13.613,-4.037,0]}],"ix":2},"a":{"a":0,"k":[11.613,-84.537,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[0,-26.924],[26.924,0],[0,26.924],[-26.924,0]],"o":[[0,26.924],[-26.924,0],[0,-26.924],[26.924,0]],"v":[[60.363,-84.537],[11.613,-35.787],[-37.137,-84.537],[11.613,-133.287]],"c":true}]},{"t":14,"s":[{"i":[[0,-25.609],[26.234,0],[0,25.609],[-26.234,0]],"o":[[0,25.609],[-26.234,0],[0,-25.609],[26.234,0]],"v":[[55.5,-92.894],[8,-46.525],[-39.5,-92.894],[8,-139.262]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":-2,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Hands 2","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[11.336,11.274,0],"ix":2},"a":{"a":0,"k":[11.336,10.774,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.818},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[0,0],[-46.458,-35.583],[-24.488,-5.64]],"o":[[0,0],[8.352,6.397],[78.271,18.027]],"v":[[-141.771,-129.716],[-87.875,-16.36],[-40.512,7.89]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.182},"t":2.742,"s":[{"i":[[0,0],[-36.01,-10.9],[-24.155,1.341]],"o":[[0,0],[17.49,5.6],[69.436,6.533]],"v":[[-154.359,-38.55],[-101.24,-1.379],[-38.096,3.379]],"c":false}]},{"i":{"x":0.833,"y":0.818},"o":{"x":0.167,"y":0.167},"t":4.572,"s":[{"i":[[0,0],[-22.495,10.354],[-22.973,-2.409]],"o":[[0,0],[18.597,-8.552],[52.89,-5.679]],"v":[[-130.223,30.529],[-97.344,4.391],[-37.533,-6.68]],"c":false}]},{"i":{"x":0.833,"y":0.818},"o":{"x":0.167,"y":0.182},"t":5.486,"s":[{"i":[[0,0],[-15.738,20.981],[-22.382,-4.284]],"o":[[0,0],[16.262,-20.519],[44.618,-11.784]],"v":[[-110.655,59.818],[-92.396,11.026],[-37.251,-11.709]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.182},"t":9,"s":[{"i":[[0,0],[15.091,34.278],[-16.072,17.731]],"o":[[0,0],[-7.208,-22.817],[16.812,-10.179]],"v":[[-13.011,129.282],[-62.232,89.104],[-50.644,19.509]],"c":false}]},{"i":{"x":0.833,"y":0.818},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[19.6,34.344],[-11.896,20.735]],"o":[[0,0],[-10.53,-23.142],[12.875,-9.952]],"v":[[0.934,129.625],[-59.674,93.522],[-55.966,25.06]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.182},"t":11,"s":[{"i":[[0,0],[24.108,34.41],[-7.719,23.739]],"o":[[0,0],[-13.853,-23.467],[8.939,-9.725]],"v":[[1.88,129.968],[-57.117,97.94],[-61.289,30.611]],"c":false}]},{"t":14,"s":[{"i":[[0,0],[25.209,29.401],[-7.488,20.11]],"o":[[0,0],[-15.125,-17.64],[3.974,-10.674]],"v":[[6.417,130.659],[-53.875,103.64],[-63.512,36.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.818},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[0,0],[48,36.333],[11.5,1.167]],"o":[[0,0],[-8.388,-6.35],[-79.91,-8.107]],"v":[[140.75,128.89],[94.542,23.473],[63.5,11.89]],"c":false}]},{"i":{"x":0.833,"y":0.818},"o":{"x":0.167,"y":0.182},"t":2.742,"s":[{"i":[[-0.107,1.301],[43.705,35.181],[12.499,4.424]],"o":[[1.452,-17.63],[-7.425,-6.513],[-75.279,-8.976]],"v":[[133.797,130.851],[92.055,22.64],[62.256,6.25]],"c":false}]},{"i":{"x":0.833,"y":0.818},"o":{"x":0.167,"y":0.182},"t":5.486,"s":[{"i":[[-6.276,1.09],[19.852,26.915],[21.224,10.921]],"o":[[6.157,-12.218],[-8.148,-12.585],[-54.801,-12.818]],"v":[[109.709,105.725],[104.015,23.092],[59.642,-11.414]],"c":false}]},{"i":{"x":0.833,"y":0.818},"o":{"x":0.167,"y":0.182},"t":9,"s":[{"i":[[-14.16,0.82],[-3.078,22.988],[16.441,25.833]],"o":[[22.052,-4.736],[2.47,-14.595],[-28.631,-17.728]],"v":[[32.732,128.976],[84.858,79.012],[68.64,15.393]],"c":false}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.182},"t":11,"s":[{"i":[[-18.622,0.668],[-13.293,19.932],[12.19,32.742]],"o":[[37.47,-1.344],[5.361,-8.677],[-13.817,-20.508]],"v":[[7.53,130.546],[77.418,98.03],[80.302,30.109]],"c":false}]},{"t":14,"s":[{"i":[[-19.233,1.202],[-15.167,22.777],[7,26.11]],"o":[[30.25,-1.89],[5.831,-8.757],[-6.192,-23.095]],"v":[[11.75,130.39],[78.167,98.723],[84,36.89]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":12,"st":-2,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Body 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.5,"y":0},"t":0,"s":[266.426,392.378,0],"to":[0,0,0],"ti":[0,0,0]},{"t":14,"s":[253.676,337.378,0]}],"ix":2},"a":{"a":0,"k":[10.676,136.378,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":0,"s":[{"i":[[-10.795,-2.32],[-8.2,-0.399],[0,0],[3,-1.298],[6.05,-16.428],[20.1,0],[6.7,14.68],[-1.7,58.223]],"o":[[7.9,1.698],[0,0],[22.2,0],[0,0],[-7.825,16.029],[-20.1,0],[-4.4,-9.787],[-11.1,-3.196]],"v":[[-40.2,-2.303],[-15.1,1.492],[56.9,1.592],[64.619,22.065],[63.2,120.034],[13.2,136.312],[-36.8,120.034],[-40.9,18.07]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[-7.729,4.405],[-14.608,0.316],[-11.697,-7.483],[-0.238,-10.621],[7.036,-14.499],[18.581,0],[6.908,15.026],[-1.237,40.257]],"o":[[7.771,-9.845],[25.241,-0.704],[10.053,2.017],[0,0],[-6.792,14.491],[-18.581,0],[-5.829,-11.041],[-0.133,-10.892]],"v":[[-35.485,-12.023],[0.894,-25.934],[52.233,-18.385],[61.774,26.253],[58.326,106.281],[12.028,125.952],[-35.105,105.616],[-40.582,23.524]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[-4.018,5.73],[-11.874,0.331],[-0.482,-11.186],[1.315,-6.931],[7.788,-13.027],[17.423,0],[7.066,15.289],[-0.885,26.553]],"o":[[3.929,-18.735],[44.497,-1.242],[7.668,7.255],[0,0],[-6.004,13.318],[-17.423,0],[-6.92,-11.998],[0.031,-13.41]],"v":[[-38.5,-13.268],[1.196,-38.483],[57.046,-13.793],[59.603,29.448],[54.608,95.788],[11.134,118.049],[-33.812,94.617],[-40.339,27.685]],"c":true}]},{"t":14,"s":[{"i":[[-0.661,9.718],[-13.678,-0.71],[-0.721,-16.729],[0.48,-9.722],[8.649,-11.342],[16.096,0],[7.247,15.59],[-0.48,10.861]],"o":[[1.962,-28.86],[25.305,1.314],[0.467,10.849],[0,0],[-5.101,11.975],[-16.096,0],[-8.168,-13.094],[0.521,-13.007]],"v":[[-37.657,-18.701],[9.27,-58.29],[57.118,-21.416],[57.118,33.106],[50.351,83.775],[10.111,109],[-32.332,82.023],[-37.817,32.45]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":13,"st":-2,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Line","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[3.687,-6.898,0],"ix":2},"a":{"a":0,"k":[3.6,-7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.1,"y":0},"t":8,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-87.744,-97.736],[94.944,83.736]],"c":false}]},{"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-101.6,-111.5],[108.8,97.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":8.143,"s":[65]},{"t":23.857421875,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":8,"s":[22]},{"t":23.857421875,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path-10","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":15,"op":36,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Head Mic","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-3.6,-33.55,0],"ix":2},"a":{"a":0,"k":[-3.6,-33.55,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.32,"y":0},"t":12,"s":[{"i":[[-26.211,0],[-0.75,-24.287],[0,0],[8.887,-9.825],[0,0],[0,0],[0,0]],"o":[[26.211,0],[0,0],[0,11.606],[0,0],[0,0],[0,0],[-1,-21.796]],"v":[[-3.735,-109.75],[45.281,-65.463],[43.991,8.35],[34.343,45.154],[-28.222,-7.666],[-50.958,-26.52],[-50.969,-65.204]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[3.254,-6.84],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.715,-109.619],[43.599,-65.808],[42.504,7.127],[37.527,30.34],[-24.609,-26.91],[-49.585,-52.154],[-50.153,-65.37]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[2.173,-4.255],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.699,-110.688],[43.436,-66.58],[42.49,6.771],[35.692,29.42],[-20.918,-24.458],[-49.597,-54.517],[-50.078,-66.202]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":17,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[2.511,-3.584],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.668,-112.826],[43.111,-68.124],[42.462,6.058],[35.521,27.954],[-13.534,-19.556],[-49.621,-59.243],[-49.928,-67.865]],"c":true}]},{"t":25,"s":[{"i":[[-25.4,0],[0,-25.4],[0,0],[6.9,-8],[0,0],[0,0],[0,0]],"o":[[25.4,0],[0,0],[0,11.4],[0,0],[0,0],[0,0],[0,-25.4]],"v":[[-3.6,-117.5],[42.4,-71.5],[42.4,4.5],[31.3,34.4],[-20.33,-17.23],[-49.6,-46.5],[-49.6,-71.5]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.32,"y":0},"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[6.088,0],[-0.503,31.164],[0,0]],"o":[[0,0],[0,0],[0,0],[-10.319,13.723],[-26.211,0],[0,0],[0,0]],"v":[[-50.984,-30.364],[-31.444,-15.166],[-26.333,-11.224],[33.943,44.851],[-3.477,59],[-50.945,10.019],[-50.958,-21.446]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[0,0],[-0.064,2.378],[0,0],[0,0],[6.019,0],[-0.47,30.673],[0,0]],"o":[[0,0],[0.089,-3.285],[0,0],[-10.163,17.808],[-25.911,0],[0,0],[0,0]],"v":[[-50.431,-27.196],[-50.235,-36.056],[-34.964,-26.612],[35.415,38.984],[-3.485,57.977],[-50.411,9.433],[-50.391,-18.196]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[-0.174,6.439],[0,0],[0,0],[5.9,0],[-0.415,29.833],[0,0]],"o":[[0,0],[0.241,-8.895],[0,0],[-9.897,24.787],[-25.4,0],[0,0],[0,0]],"v":[[-49.489,-21.787],[-49.835,-35.855],[-49.705,-52.894],[37.928,28.963],[-3.499,56.229],[-49.499,8.433],[-49.422,-12.646]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[-0.361,29.258],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.945,8.024],[-25.4,0],[0,0],[0,0]],"v":[[-49.614,-15.443],[-16.569,15.355],[-4.062,27.479],[16.726,47.226],[-3.512,55.472],[-49.512,7.909],[-49.493,-12.332]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":17,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[-0.253,28.106],[0,0]],"o":[[0,0],[0,0],[0,0],[-4.54,4.12],[-25.4,0],[0,0],[0,0]],"v":[[-49.647,-16.255],[-37.036,-2.726],[-33.526,0.224],[15.322,49.25],[-3.538,53.958],[-49.538,6.862],[-49.634,-11.706]],"c":true}]},{"t":25,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[5.9,0],[0,25.4],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.2,2],[-25.4,0],[0,0],[0,0]],"v":[[-49.6,-15.4],[-40.702,-6.502],[-38.75,-4.55],[13.1,47.3],[-3.6,50.4],[-49.6,4.4],[-49.6,-15.4]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":36,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Arc L","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.05,"y":0},"t":15,"s":[-3.781,80.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.69,"y":1},"o":{"x":0.31,"y":0},"t":25,"s":[-3.781,89.75,0],"to":[0,0,0],"ti":[0,0,0]},{"t":33,"s":[-3.75,84.5,0]}],"ix":2},"a":{"a":0,"k":[-3.75,84.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.1,"y":0},"t":12,"s":[{"i":[[0,0],[13.1,0],[-24.469,59.5]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[32,72.5],[-6,80],[-74,-20]],"c":false}]},{"t":26,"s":[{"i":[[0,0],[13.1,0],[0,42]],"o":[[-11,5.1],[-45.3,0],[0,0]],"v":[[33,76.5],[-3.5,84.5],[-85.5,6.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":36,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Arc R","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[66.05,51.45,0],"ix":2},"a":{"a":0,"k":[66.05,51.45,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.1,"y":0},"t":12,"s":[{"i":[[0,0],[39.331,-15]],"o":[[9.631,29.1],[0,0]],"v":[[68.4,-20.1],[39.2,68.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[38.51,-16.677]],"o":[[5.914,24.45],[0,0]],"v":[[72.925,-10.242],[39.451,70.103]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[10.82,-9.511]],"o":[[4.75,22.994],[0,0]],"v":[[74.342,-7.154],[65.462,49.587]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":19,"s":[{"i":[[0,0],[13.536,-11.424]],"o":[[1.257,18.625],[0,0]],"v":[[78.594,2.109],[61.495,50.04]],"c":false}]},{"t":26,"s":[{"i":[[0,0],[8.7,-12]],"o":[[0,15.6],[0,0]],"v":[[78.4,8.4],[64.7,50.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":22,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":36,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Leg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252.45,380.6,0],"ix":2},"a":{"a":0,"k":[-3.55,124.6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.1,"y":0},"t":11,"s":[{"i":[[-11.972,0],[0,0],[0,-2.631],[0,0],[11.972,0],[0,0],[0,2.631],[0,0]],"o":[[0,0],[11.972,0],[0,0],[0,2.631],[0,0],[-11.972,0],[0,0],[0,-2.631]],"v":[[-6.686,71.5],[-0.414,71.5],[21.25,76.26],[21.25,85.99],[-0.414,90.75],[-6.686,90.75],[-28.35,85.99],[-28.35,76.26]],"c":true}]},{"i":{"x":0.69,"y":1},"o":{"x":0.31,"y":0},"t":20,"s":[{"i":[[-6.3,0],[0,0],[0,-4.763],[0,0],[6.3,0],[0,0],[0,4.763],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,4.763],[0,0],[-6.3,0],[0,0],[0,-4.763]],"v":[[-5.2,89.75],[-1.9,89.75],[9.5,98.368],[9.5,115.982],[-1.9,124.6],[-5.2,124.6],[-16.6,115.982],[-16.6,98.368]],"c":true}]},{"t":33,"s":[{"i":[[-6.3,0],[0,0],[0,-6.3],[0,0],[6.3,0],[0,0],[0,6.3],[0,0]],"o":[[0,0],[6.3,0],[0,0],[0,6.3],[0,0],[-6.3,0],[0,0],[0,-6.3]],"v":[[-5.2,78.5],[-1.9,78.5],[9.5,89.9],[9.5,113.2],[-1.9,124.6],[-5.2,124.6],[-16.6,113.2],[-16.6,89.9]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":11,"op":36,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Start Chat to Mute Android 3","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":376,"op":405,"st":376,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Cancel Reminder to Mute Android","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":344,"op":376,"st":344,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Set Reminder Android","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":311,"op":344,"st":311,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Cancel Reminder to Rise Hand","refId":"comp_6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":274,"op":311,"st":274,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Set Reminder to Rise Hand","refId":"comp_8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":237,"op":274,"st":237,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Set Reminder to Mute","refId":"comp_10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":202,"op":237,"st":202,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Cancel Reminder","refId":"comp_12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":173,"op":202,"st":173,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Unmute to Rise Hand","refId":"comp_14","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":136,"op":173,"st":136,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"Mute to Rise Hand","refId":"comp_16","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":99,"op":136,"st":99,"bm":0},{"ddd":0,"ind":10,"ty":0,"nm":"Mute","refId":"comp_18","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":69,"op":99,"st":69,"bm":0},{"ddd":0,"ind":11,"ty":0,"nm":"Unmute Android","refId":"comp_20","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":36,"op":69,"st":36,"bm":0},{"ddd":0,"ind":12,"ty":0,"nm":"Raise Hand to Mute","refId":"comp_22","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":60,"h":60,"ip":0,"op":36,"st":0,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_desktop_mac.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"mac_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle 21","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,20.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[],"ip":0,"op":120,"st":-120,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle 23","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,22,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-0.276],[-0.828,0],[0,0],[0,0.828],[0.276,0]],"o":[[-0.276,0],[0,0.828],[0,0],[0.828,0],[0,-0.276],[0,0]],"v":[[-12.5,-1],[-13,-0.5],[-11.5,1],[11.5,1],[13,-0.5],[12.5,-1]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Rectangle 22","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-120,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Rectangle 22","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,22,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-0.276],[-0.828,0],[0,0],[0,0.828],[0.276,0]],"o":[[-0.276,0],[0,0.828],[0,0],[0.828,0],[0,-0.276],[0,0]],"v":[[-12.5,-17.667],[-13,-0.5],[-11.5,1],[11.5,1],[13,-0.5],[12.5,-17.667]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Rectangle 22","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-120,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Rectangle 21","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[15,15,0],"to":[0,1.083,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":20,"s":[15,21.5,0],"to":[0,0,0],"ti":[0,1.083,0]},{"t":40,"s":[15,15,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0.192,-0.376],[0,-1.12],[0,0],[0,0],[0,0],[0.218,0.428],[0.376,0.192],[1.12,0],[0,0],[0.428,-0.218]],"o":[[-0.218,0.428],[0,0],[0,0],[0,0],[0,-1.12],[-0.192,-0.376],[-0.428,-0.218],[0,0],[-1.12,0],[-0.376,0.192]],"v":[[-8.782,-5.908],[-9,-3.8],[-9,7],[9,7],[9,-3.8],[8.782,-5.908],[7.908,-6.782],[5.8,-7],[-5.8,-7],[-7.908,-6.782]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":20,"s":[{"i":[[0.256,-0.027],[0,-0.08],[0,0],[0,0],[0,0],[0.291,0.031],[0.502,0.014],[1.493,0],[0,0],[0.57,-0.016]],"o":[[-0.291,0.031],[0,0],[0,0],[0,0],[0,-0.08],[-0.256,-0.027],[-0.57,-0.016],[0,0],[-1.493,0],[-0.502,0.014]],"v":[[-11.709,-0.422],[-12,-0.271],[-12,0.5],[12,0.5],[12,-0.271],[11.709,-0.422],[10.544,-0.484],[7.733,-0.5],[-7.733,-0.5],[-10.544,-0.484]],"c":true}]},{"t":40,"s":[{"i":[[0.192,-0.376],[0,-1.12],[0,0],[0,0],[0,0],[0.218,0.428],[0.376,0.192],[1.12,0],[0,0],[0.428,-0.218]],"o":[[-0.218,0.428],[0,0],[0,0],[0,0],[0,-1.12],[-0.192,-0.376],[-0.428,-0.218],[0,0],[-1.12,0],[-0.376,0.192]],"v":[[-8.782,-5.908],[-9,-3.8],[-9,7],[9,7],[9,-3.8],[8.782,-5.908],[7.908,-6.782],[5.8,-7],[-5.8,-7],[-7.908,-6.782]],"c":true}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Rectangle 21","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-120,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"apple 2","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.955,-1.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[1,1,0.333],"y":[0,0,0]},"t":20,"s":[40,0,100]},{"t":40,"s":[80,80,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.31,0.445],[-0.161,0.375],[-0.056,0.176],[0.222,0.21],[0.009,0.704],[-0.829,0.5],[0.927,0.074],[0.494,-0.176],[0.093,0],[0.431,0.162],[0.264,0],[0.409,-0.246],[0.242,-0.418],[0,-0.737],[-0.236,-0.686],[-0.359,-0.515],[-0.213,-0.185],[-0.334,0.014],[-0.357,0.144],[-0.344,0.006],[-0.307,-0.133],[-0.25,0],[-0.306,0.278]],"o":[[0.234,-0.334],[0.07,-0.162],[-0.28,-0.122],[-0.5,-0.463],[-0.009,-0.899],[-0.463,-0.658],[-0.34,-0.028],[-0.524,0.19],[-0.12,0],[-0.431,-0.162],[-0.477,0.005],[-0.414,0.248],[-0.32,0.533],[0,0.644],[0.201,0.594],[0.32,0.449],[0.334,0.31],[0.222,-0.009],[0.317,-0.135],[0.335,0.007],[0.352,0.148],[0.347,-0.009],[0.195,-0.171]],"v":[[3.848,4.137],[4.441,3.071],[4.631,2.566],[3.871,2.066],[3.107,0.315],[4.334,-1.789],[2.249,-2.887],[0.998,-2.665],[0.076,-2.377],[-0.753,-2.623],[-1.8,-2.868],[-3.153,-2.484],[-4.154,-1.469],[-4.631,0.435],[-4.274,2.427],[-3.431,4.1],[-2.634,5.054],[-1.633,5.499],[-0.767,5.272],[0.234,5.059],[1.207,5.272],[2.11,5.49],[3.088,5.059]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-0.482,0.565],[0,0.551],[0.005,0.074],[0.277,-0.142],[0.217,-0.246],[0,-0.528],[-0.01,-0.069]],"o":[[0.403,-0.473],[0,-0.074],[-0.31,0.023],[-0.297,0.139],[-0.408,0.463],[0,0.07],[0.63,0.051]],"v":[[1.717,-3.739],[2.319,-5.278],[2.31,-5.5],[1.42,-5.25],[0.642,-4.666],[0.002,-3.109],[0.016,-2.901]],"c":true},"ix":2},"nm":"Контур 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Объединить контуры 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"apple","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-120,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_desktop_win.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"windows_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Union","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[15]},{"i":{"x":[0.833],"y":[0.889]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[12.5]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.222]},"t":35,"s":[15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":55,"s":[17.5]},{"t":70,"s":[15]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[15]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[15]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":35,"s":[15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":55,"s":[15]},{"t":70,"s":[15]}],"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-1,11],[-1,1],[-12.667,1],[-12.667,-1],[-1,-1],[-1,-11],[1,-11],[1,-1],[12.667,-1],[12.667,1],[1,1],[1,11]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Union","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle 23","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9,-9],[9,9],[-9,9],[-9,-9]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":25,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9,-10.667],[9,10.667],[-10.667,5.667],[-10.667,-5.667]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":35,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9,-9],[9,9],[-9,9],[-9,-9]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":55,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[10.667,-5.667],[10.667,5.667],[-9,10.667],[-9,-10.667]],"c":true}]},{"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9,-9],[9,9],[-9,9],[-9,-9]],"c":true}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Rectangle 23","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_linux.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"linux_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector 25","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[15,21.686,0],"to":[0,0.069,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[15,22.103,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[15,21.686,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":30,"s":[15,22.103,0],"to":[0,0,0],"ti":[0,0.069,0]},{"t":40,"s":[15,21.686,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-0.452,0.127],[-1.798,0],[-1.471,-0.414],[0.428,-0.195],[1.333,-1.348],[0.372,0.376],[1.412,0.643]],"o":[[1.471,-0.414],[1.798,0],[0.452,0.127],[-1.412,0.643],[-0.372,0.376],[-1.333,-1.348],[-0.428,-0.195]],"v":[[-5.66,-1.69],[0,-2.686],[5.66,-1.69],[5.712,-0.738],[0.726,2.404],[-0.726,2.404],[-5.712,-0.738]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[-0.452,0.127],[-1.798,0],[-1.471,-0.414],[0.428,-0.195],[1.333,-1.348],[0.372,0.376],[1.412,0.643]],"o":[[1.471,-0.414],[1.798,0],[0.452,0.127],[-1.412,0.643],[-0.372,0.376],[-1.333,-1.348],[-0.428,-0.195]],"v":[[-5.66,-1.69],[0,-2.686],[5.66,-1.69],[5.712,-0.738],[0.726,2.821],[-0.726,2.821],[-5.712,-0.738]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[{"i":[[-0.452,0.127],[-1.798,0],[-1.471,-0.414],[0.428,-0.195],[1.333,-1.348],[0.372,0.376],[1.412,0.643]],"o":[[1.471,-0.414],[1.798,0],[0.452,0.127],[-1.412,0.643],[-0.372,0.376],[-1.333,-1.348],[-0.428,-0.195]],"v":[[-5.66,-1.69],[0,-2.686],[5.66,-1.69],[5.712,-0.738],[0.726,2.404],[-0.726,2.404],[-5.712,-0.738]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":30,"s":[{"i":[[-0.452,0.127],[-1.798,0],[-1.471,-0.414],[0.428,-0.195],[1.333,-1.348],[0.372,0.376],[1.412,0.643]],"o":[[1.471,-0.414],[1.798,0],[0.452,0.127],[-1.412,0.643],[-0.372,0.376],[-1.333,-1.348],[-0.428,-0.195]],"v":[[-5.66,-1.69],[0,-2.686],[5.66,-1.69],[5.712,-0.738],[0.726,2.821],[-0.726,2.821],[-5.712,-0.738]],"c":true}]},{"t":40,"s":[{"i":[[-0.452,0.127],[-1.798,0],[-1.471,-0.414],[0.428,-0.195],[1.333,-1.348],[0.372,0.376],[1.412,0.643]],"o":[[1.471,-0.414],[1.798,0],[0.452,0.127],[-1.412,0.643],[-0.372,0.376],[-1.333,-1.348],[-0.428,-0.195]],"v":[[-5.66,-1.69],[0,-2.686],[5.66,-1.69],[5.712,-0.738],[0.726,2.404],[-0.726,2.404],[-5.712,-0.738]],"c":true}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Vector 25","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Ellipse 28","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[19,16.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":10,"s":[20,5,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":30,"s":[20,5,100]},{"t":40,"s":[16.667,16.667,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[2,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Ellipse 28","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Ellipse 27","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[11,16.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":10,"s":[20,5,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":30,"s":[20,5,100]},{"t":40,"s":[16.667,16.667,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[2,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Ellipse 27","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Subtract","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,12,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,1.422],[-5.523,0],[0,-5.523],[0.535,-1.225],[0,0],[2.761,0],[0.81,-1.668],[1.979,0],[0,-2.761],[0,0]],"o":[[0,-5.523],[5.523,0],[0,1.422],[0,0],[0,-2.761],[-1.979,0],[-0.81,-1.668],[-2.761,0],[0,0],[-0.535,-1.225]],"v":[[-10,3],[0,-7],[10,3],[9.168,7],[9.5,5],[4.5,0],[0,2.818],[-4.5,0],[-9.5,5],[-9.168,7]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[0,1.422],[-5.523,0],[0,-5.523],[0.535,-1.225],[0,0],[2.761,0],[0.81,-1.668],[1.979,0],[0,-2.761],[0,0]],"o":[[0,-5.523],[5.523,0],[0,1.422],[0,0],[0,-2.761],[-1.979,0],[-0.81,-1.668],[-2.761,0],[0,0],[-0.535,-1.225]],"v":[[-10,3],[0,-7],[10,3],[9.168,7],[9.5,5],[4.5,1.25],[0,4.068],[-4.5,1.25],[-9.5,5],[-9.168,7]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[{"i":[[0,1.422],[-5.523,0],[0,-5.523],[0.535,-1.225],[0,0],[2.761,0],[0.81,-1.668],[1.979,0],[0,-2.761],[0,0]],"o":[[0,-5.523],[5.523,0],[0,1.422],[0,0],[0,-2.761],[-1.979,0],[-0.81,-1.668],[-2.761,0],[0,0],[-0.535,-1.225]],"v":[[-10,3],[0,-7],[10,3],[9.168,7],[9.5,5],[4.5,0],[0,2.818],[-4.5,0],[-9.5,5],[-9.168,7]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":30,"s":[{"i":[[0,1.422],[-5.523,0],[0,-5.523],[0.535,-1.225],[0,0],[2.761,0],[0.81,-1.668],[1.979,0],[0,-2.761],[0,0]],"o":[[0,-5.523],[5.523,0],[0,1.422],[0,0],[0,-2.761],[-1.979,0],[-0.81,-1.668],[-2.761,0],[0,0],[-0.535,-1.225]],"v":[[-10,3],[0,-7],[10,3],[9.168,7],[9.5,5],[4.5,1.25],[0,4.068],[-4.5,1.25],[-9.5,5],[-9.168,7]],"c":true}]},{"t":40,"s":[{"i":[[0,1.422],[-5.523,0],[0,-5.523],[0.535,-1.225],[0,0],[2.761,0],[0.81,-1.668],[1.979,0],[0,-2.761],[0,0]],"o":[[0,-5.523],[5.523,0],[0,1.422],[0,0],[0,-2.761],[-1.979,0],[-0.81,-1.668],[-2.761,0],[0,0],[-0.535,-1.225]],"v":[[-10,3],[0,-7],[10,3],[9.168,7],[9.5,5],[4.5,0],[0,2.818],[-4.5,0],[-9.5,5],[-9.168,7]],"c":true}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Subtract","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_linux_ubuntu.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"ubuntu_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Union","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[13.594,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-4.297,-5.178],[-6.797,-9.508],[-8.234,-8.678],[-5.734,-4.348]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-8.234,8.678],[-5.734,4.348],[-4.297,5.178],[-6.797,9.508]],"c":true},"ix":2},"nm":"Контур 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[3.234,0.83],[8.234,0.83],[8.234,-0.83],[3.234,-0.83]],"c":true},"ix":2},"nm":"Контур 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Объединить контуры 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Union","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Ellipse 24","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,51.962,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[-100,-100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":15,"s":[-70,-70,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[-130,-130,100]},{"t":30,"s":[-100,-100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[4,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2.66,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":60,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Ellipse 24","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Ellipse 24","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-60,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[-100,-100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":15,"s":[-70,-70,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[-130,-130,100]},{"t":30,"s":[-100,-100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[4,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2.66,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Ellipse 24","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Ellipse 25","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,-51.961,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[-100,-100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":15,"s":[-70,-70,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[-130,-130,100]},{"t":30,"s":[-100,-100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[4,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2.66,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":-60,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Ellipse 24","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Ellipse 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[-245]},{"t":30,"s":[-240]}],"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Ellipse 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_phone_android.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"android_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Eye L","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[10.5,16,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":10,"s":[20,5,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":30,"s":[20,5,100]},{"t":40,"s":[16.667,16.667,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3,3],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Eye L","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Eye R","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[19.5,16,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":10,"s":[20,5,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":30,"s":[20,5,100]},{"t":40,"s":[16.667,16.667,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3,3],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Eye R","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Face","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,15.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.335,1.25],[-4.973,0],[-1.361,-5.079],[0.382,-0.702],[0.129,-0.123],[1.573,0],[0,0],[0.579,0.551],[0.085,0.157]],"o":[[1.361,-5.079],[4.973,0],[0.335,1.25],[-0.085,0.157],[-0.579,0.551],[0,0],[-1.573,0],[-0.129,-0.123],[-0.382,-0.702]],"v":[[-10.536,2.379],[0,-6],[10.536,2.379],[10.657,4.957],[10.279,5.449],[7.34,6],[-7.34,6],[-10.279,5.449],[-10.657,4.957]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Face","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Ri","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.75,9.75,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[1.25,-2.25],[-1.25,2.25]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.5,-1],[-1.25,2.25]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[1.25,-2.25],[-1.25,2.25]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":30,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.5,-1],[-1.25,2.25]],"c":false}]},{"t":40,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[1.25,-2.25],[-1.25,2.25]],"c":false}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1.66,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Ri","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Le","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.25,9.75,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-1.25,-2.25],[1.25,2.25]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.5,-1],[1.25,2.25]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-1.25,-2.25],[1.25,2.25]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":30,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.5,-1],[1.25,2.25]],"c":false}]},{"t":40,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-1.25,-2.25],[1.25,2.25]],"c":false}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1.66,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Le","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_phone_ios.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"iphone_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"apple","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[14.841,14.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":10,"s":[0,13.333,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[1,1,0.333],"y":[0,0,0]},"t":20,"s":[15,15,100]},{"t":30,"s":[0,13.333,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.31,0.445],[-0.161,0.375],[-0.056,0.176],[0.222,0.21],[0.009,0.704],[-0.829,0.5],[0.927,0.074],[0.494,-0.176],[0.093,0],[0.431,0.162],[0.264,0],[0.409,-0.246],[0.242,-0.418],[0,-0.737],[-0.236,-0.686],[-0.359,-0.515],[-0.213,-0.185],[-0.334,0.014],[-0.357,0.144],[-0.344,0.006],[-0.307,-0.133],[-0.25,0],[-0.306,0.278]],"o":[[0.234,-0.334],[0.07,-0.162],[-0.28,-0.122],[-0.5,-0.463],[-0.009,-0.899],[-0.463,-0.658],[-0.34,-0.028],[-0.524,0.19],[-0.12,0],[-0.431,-0.162],[-0.477,0.005],[-0.414,0.248],[-0.32,0.533],[0,0.644],[0.201,0.594],[0.32,0.449],[0.334,0.31],[0.222,-0.009],[0.317,-0.135],[0.335,0.007],[0.352,0.148],[0.347,-0.009],[0.195,-0.171]],"v":[[3.848,4.137],[4.441,3.071],[4.631,2.566],[3.871,2.066],[3.107,0.315],[4.334,-1.789],[2.249,-2.887],[0.998,-2.665],[0.076,-2.377],[-0.753,-2.623],[-1.8,-2.868],[-3.153,-2.484],[-4.154,-1.469],[-4.631,0.435],[-4.274,2.427],[-3.431,4.1],[-2.634,5.054],[-1.633,5.499],[-0.767,5.272],[0.234,5.059],[1.207,5.272],[2.11,5.49],[3.088,5.059]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-0.482,0.565],[0,0.551],[0.005,0.074],[0.277,-0.142],[0.217,-0.246],[0,-0.528],[-0.01,-0.069]],"o":[[0.403,-0.473],[0,-0.074],[-0.31,0.023],[-0.297,0.139],[-0.408,0.463],[0,0.07],[0.63,0.051]],"v":[[1.717,-3.739],[2.319,-5.278],[2.31,-5.5],[1.42,-5.25],[0.642,-4.666],[0.002,-3.109],[0.016,-2.901]],"c":true},"ix":2},"nm":"Контур 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Объединить контуры 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"apple","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-120,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector 39","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,6,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,-0.884],[0.221,0],[0,0],[0,0.221],[0.884,0],[0,0]],"o":[[0,0],[-0.884,0],[0,0.221],[0,0],[-0.221,0],[0,-0.884],[0,0],[0,0]],"v":[[4,-1],[3.6,-1],[2,0.6],[1.6,1],[-1.6,1],[-2,0.6],[-3.6,-1],[-4,-1]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[0,0],[0,-0.884],[0.028,0],[0,0],[0,0.221],[0.11,0],[0,0]],"o":[[0,0],[-0.11,0],[0,0.221],[0,0],[-0.028,0],[0,-0.884],[0,0],[0,0]],"v":[[0.5,-1],[0.45,-1],[0.25,0.6],[0.2,1],[-0.2,1],[-0.25,0.6],[-0.45,-1],[-0.5,-1]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[0,0],[0,0],[0,-0.884],[0.028,0],[0,0],[0,0.221],[0.11,0],[0,0]],"o":[[0,0],[-0.11,0],[0,0.221],[0,0],[-0.028,0],[0,-0.884],[0,0],[0,0]],"v":[[0.5,-1],[0.45,-1],[0.25,0.6],[0.2,1],[-0.2,1],[-0.25,0.6],[-0.45,-1],[-0.5,-1]],"c":false}]},{"t":40,"s":[{"i":[[0,0],[0,0],[0,-0.884],[0.221,0],[0,0],[0,0.221],[0.884,0],[0,0]],"o":[[0,0],[-0.884,0],[0,0.221],[0,0],[-0.221,0],[0,-0.884],[0,0],[0,0]],"v":[[4,-1],[3.6,-1],[2,0.6],[1.6,1],[-1.6,1],[-2,0.6],[-3.6,-1],[-4,-1]],"c":false}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Vector 39","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-120,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Rectangle 21","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0.192,-0.376],[0,-1.12],[0,0],[-0.218,-0.428],[-0.376,-0.192],[-1.12,0],[0,0],[-0.428,0.218],[-0.192,0.376],[0,1.12],[0,0],[0.218,0.428],[0.376,0.192],[1.12,0],[0,0],[0.428,-0.218]],"o":[[-0.218,0.428],[0,0],[0,1.12],[0.192,0.376],[0.428,0.218],[0,0],[1.12,0],[0.376,-0.192],[0.218,-0.428],[0,0],[0,-1.12],[-0.192,-0.376],[-0.428,-0.218],[0,0],[-1.12,0],[-0.376,0.192]],"v":[[-5.782,-8.908],[-6,-6.8],[-6,6.8],[-5.782,8.908],[-4.908,9.782],[-2.8,10],[2.8,10],[4.908,9.782],[5.782,8.908],[6,6.8],[6,-6.8],[5.782,-8.908],[4.908,-9.782],[2.8,-10],[-2.8,-10],[-4.908,-9.782]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0.016,-0.376],[0,-1.12],[0,0],[-0.018,-0.428],[-0.031,-0.192],[-0.093,0],[0,0],[-0.036,0.218],[-0.016,0.376],[0,1.12],[0,0],[0.018,0.428],[0.031,0.192],[0.093,0],[0,0],[0.036,-0.218]],"o":[[-0.018,0.428],[0,0],[0,1.12],[0.016,0.376],[0.036,0.218],[0,0],[0.093,0],[0.031,-0.192],[0.018,-0.428],[0,0],[0,-1.12],[-0.016,-0.376],[-0.036,-0.218],[0,0],[-0.093,0],[-0.031,0.192]],"v":[[-0.482,-8.908],[-0.5,-6.8],[-0.5,6.8],[-0.482,8.908],[-0.409,9.782],[-0.233,10],[0.233,10],[0.409,9.782],[0.482,8.908],[0.5,6.8],[0.5,-6.8],[0.482,-8.908],[0.409,-9.782],[0.233,-10],[-0.233,-10],[-0.409,-9.782]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":1,"y":0},"t":20,"s":[{"i":[[0.192,-0.376],[0,-1.12],[0,0],[-0.218,-0.428],[-0.376,-0.192],[-1.12,0],[0,0],[-0.428,0.218],[-0.192,0.376],[0,1.12],[0,0],[0.218,0.428],[0.376,0.192],[1.12,0],[0,0],[0.428,-0.218]],"o":[[-0.218,0.428],[0,0],[0,1.12],[0.192,0.376],[0.428,0.218],[0,0],[1.12,0],[0.376,-0.192],[0.218,-0.428],[0,0],[0,-1.12],[-0.192,-0.376],[-0.428,-0.218],[0,0],[-1.12,0],[-0.376,0.192]],"v":[[-5.782,-8.908],[-6,-6.8],[-6,6.8],[-5.782,8.908],[-4.908,9.782],[-2.8,10],[2.8,10],[4.908,9.782],[5.782,8.908],[6,6.8],[6,-6.8],[5.782,-8.908],[4.908,-9.782],[2.8,-10],[-2.8,-10],[-4.908,-9.782]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[0.016,-0.376],[0,-1.12],[0,0],[-0.018,-0.428],[-0.031,-0.192],[-0.093,0],[0,0],[-0.036,0.218],[-0.016,0.376],[0,1.12],[0,0],[0.018,0.428],[0.031,0.192],[0.093,0],[0,0],[0.036,-0.218]],"o":[[-0.018,0.428],[0,0],[0,1.12],[0.016,0.376],[0.036,0.218],[0,0],[0.093,0],[0.031,-0.192],[0.018,-0.428],[0,0],[0,-1.12],[-0.016,-0.376],[-0.036,-0.218],[0,0],[-0.093,0],[-0.031,0.192]],"v":[[-0.482,-8.908],[-0.5,-6.8],[-0.5,6.8],[-0.482,8.908],[-0.409,9.782],[-0.233,10],[0.233,10],[0.409,9.782],[0.482,8.908],[0.5,6.8],[0.5,-6.8],[0.482,-8.908],[0.409,-9.782],[0.233,-10],[-0.233,-10],[-0.409,-9.782]],"c":true}]},{"t":40,"s":[{"i":[[0.192,-0.376],[0,-1.12],[0,0],[-0.218,-0.428],[-0.376,-0.192],[-1.12,0],[0,0],[-0.428,0.218],[-0.192,0.376],[0,1.12],[0,0],[0.218,0.428],[0.376,0.192],[1.12,0],[0,0],[0.428,-0.218]],"o":[[-0.218,0.428],[0,0],[0,1.12],[0.192,0.376],[0.428,0.218],[0,0],[1.12,0],[0.376,-0.192],[0.218,-0.428],[0,0],[0,-1.12],[-0.192,-0.376],[-0.428,-0.218],[0,0],[-1.12,0],[-0.376,0.192]],"v":[[-5.782,-8.908],[-6,-6.8],[-6,6.8],[-5.782,8.908],[-4.908,9.782],[-2.8,10],[2.8,10],[4.908,9.782],[5.782,8.908],[6,6.8],[6,-6.8],[5.782,-8.908],[4.908,-9.782],[2.8,-10],[-2.8,-10],[-4.908,-9.782]],"c":true}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"rd","nm":"Скругленные углы 1","r":{"a":0,"k":2,"ix":1},"ix":2,"mn":"ADBE Vector Filter - RC","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[100]},{"t":30,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Rectangle 21","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-120,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_tablet_ios.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"ipad_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"apple","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[14.841,14.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":10,"s":[0,13.333,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[1,1,0.333],"y":[0,0,0]},"t":20,"s":[15,15,100]},{"t":30,"s":[0,13.333,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.31,0.445],[-0.161,0.375],[-0.056,0.176],[0.222,0.21],[0.009,0.704],[-0.829,0.5],[0.927,0.074],[0.494,-0.176],[0.093,0],[0.431,0.162],[0.264,0],[0.409,-0.246],[0.242,-0.418],[0,-0.737],[-0.236,-0.686],[-0.359,-0.515],[-0.213,-0.185],[-0.334,0.014],[-0.357,0.144],[-0.344,0.006],[-0.307,-0.133],[-0.25,0],[-0.306,0.278]],"o":[[0.234,-0.334],[0.07,-0.162],[-0.28,-0.122],[-0.5,-0.463],[-0.009,-0.899],[-0.463,-0.658],[-0.34,-0.028],[-0.524,0.19],[-0.12,0],[-0.431,-0.162],[-0.477,0.005],[-0.414,0.248],[-0.32,0.533],[0,0.644],[0.201,0.594],[0.32,0.449],[0.334,0.31],[0.222,-0.009],[0.317,-0.135],[0.335,0.007],[0.352,0.148],[0.347,-0.009],[0.195,-0.171]],"v":[[3.848,4.137],[4.441,3.071],[4.631,2.566],[3.871,2.066],[3.107,0.315],[4.334,-1.789],[2.249,-2.887],[0.998,-2.665],[0.076,-2.377],[-0.753,-2.623],[-1.8,-2.868],[-3.153,-2.484],[-4.154,-1.469],[-4.631,0.435],[-4.274,2.427],[-3.431,4.1],[-2.634,5.054],[-1.633,5.499],[-0.767,5.272],[0.234,5.059],[1.207,5.272],[2.11,5.49],[3.088,5.059]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-0.482,0.565],[0,0.551],[0.005,0.074],[0.277,-0.142],[0.217,-0.246],[0,-0.528],[-0.01,-0.069]],"o":[[0.403,-0.473],[0,-0.074],[-0.31,0.023],[-0.297,0.139],[-0.408,0.463],[0,0.07],[0.63,0.051]],"v":[[1.717,-3.739],[2.319,-5.278],[2.31,-5.5],[1.42,-5.25],[0.642,-4.666],[0.002,-3.109],[0.016,-2.901]],"c":true},"ix":2},"nm":"Контур 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Объединить контуры 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"apple","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-120,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle 21","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0.192,-0.376],[0,-1.12],[0,0],[-0.218,-0.428],[-0.376,-0.192],[-1.12,0],[0,0],[-0.428,0.218],[-0.192,0.376],[0,1.12],[0,0],[0.218,0.428],[0.376,0.192],[1.12,0],[0,0],[0.428,-0.218]],"o":[[-0.218,0.428],[0,0],[0,1.12],[0.192,0.376],[0.428,0.218],[0,0],[1.12,0],[0.376,-0.192],[0.218,-0.428],[0,0],[0,-1.12],[-0.192,-0.376],[-0.428,-0.218],[0,0],[-1.12,0],[-0.376,0.192]],"v":[[-7.782,-8.908],[-8,-6.8],[-8,6.8],[-7.782,8.908],[-6.908,9.782],[-4.8,10],[4.8,10],[6.908,9.782],[7.782,8.908],[8,6.8],[8,-6.8],[7.782,-8.908],[6.908,-9.782],[4.8,-10],[-4.8,-10],[-6.908,-9.782]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0.012,-0.376],[0,-1.12],[0,0],[-0.014,-0.428],[-0.024,-0.192],[-0.07,0],[0,0],[-0.027,0.218],[-0.012,0.376],[0,1.12],[0,0],[0.014,0.428],[0.024,0.192],[0.07,0],[0,0],[0.027,-0.218]],"o":[[-0.014,0.428],[0,0],[0,1.12],[0.012,0.376],[0.027,0.218],[0,0],[0.07,0],[0.024,-0.192],[0.014,-0.428],[0,0],[0,-1.12],[-0.012,-0.376],[-0.027,-0.218],[0,0],[-0.07,0],[-0.024,0.192]],"v":[[-0.486,-8.908],[-0.5,-6.8],[-0.5,6.8],[-0.486,8.908],[-0.432,9.782],[-0.3,10],[0.3,10],[0.432,9.782],[0.486,8.908],[0.5,6.8],[0.5,-6.8],[0.486,-8.908],[0.432,-9.782],[0.3,-10],[-0.3,-10],[-0.432,-9.782]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":1,"y":0},"t":20,"s":[{"i":[[0.192,-0.376],[0,-1.12],[0,0],[-0.218,-0.428],[-0.376,-0.192],[-1.12,0],[0,0],[-0.428,0.218],[-0.192,0.376],[0,1.12],[0,0],[0.218,0.428],[0.376,0.192],[1.12,0],[0,0],[0.428,-0.218]],"o":[[-0.218,0.428],[0,0],[0,1.12],[0.192,0.376],[0.428,0.218],[0,0],[1.12,0],[0.376,-0.192],[0.218,-0.428],[0,0],[0,-1.12],[-0.192,-0.376],[-0.428,-0.218],[0,0],[-1.12,0],[-0.376,0.192]],"v":[[-7.782,-8.908],[-8,-6.8],[-8,6.8],[-7.782,8.908],[-6.908,9.782],[-4.8,10],[4.8,10],[6.908,9.782],[7.782,8.908],[8,6.8],[8,-6.8],[7.782,-8.908],[6.908,-9.782],[4.8,-10],[-4.8,-10],[-6.908,-9.782]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[0.012,-0.376],[0,-1.12],[0,0],[-0.014,-0.428],[-0.024,-0.192],[-0.07,0],[0,0],[-0.027,0.218],[-0.012,0.376],[0,1.12],[0,0],[0.014,0.428],[0.024,0.192],[0.07,0],[0,0],[0.027,-0.218]],"o":[[-0.014,0.428],[0,0],[0,1.12],[0.012,0.376],[0.027,0.218],[0,0],[0.07,0],[0.024,-0.192],[0.014,-0.428],[0,0],[0,-1.12],[-0.012,-0.376],[-0.027,-0.218],[0,0],[-0.07,0],[-0.024,0.192]],"v":[[-0.486,-8.908],[-0.5,-6.8],[-0.5,6.8],[-0.486,8.908],[-0.432,9.782],[-0.3,10],[0.3,10],[0.432,9.782],[0.486,8.908],[0.5,6.8],[0.5,-6.8],[0.486,-8.908],[0.432,-9.782],[0.3,-10],[-0.3,-10],[-0.432,-9.782]],"c":true}]},{"t":40,"s":[{"i":[[0.192,-0.376],[0,-1.12],[0,0],[-0.218,-0.428],[-0.376,-0.192],[-1.12,0],[0,0],[-0.428,0.218],[-0.192,0.376],[0,1.12],[0,0],[0.218,0.428],[0.376,0.192],[1.12,0],[0,0],[0.428,-0.218]],"o":[[-0.218,0.428],[0,0],[0,1.12],[0.192,0.376],[0.428,0.218],[0,0],[1.12,0],[0.376,-0.192],[0.218,-0.428],[0,0],[0,-1.12],[-0.192,-0.376],[-0.428,-0.218],[0,0],[-1.12,0],[-0.376,0.192]],"v":[[-7.782,-8.908],[-8,-6.8],[-8,6.8],[-7.782,8.908],[-6.908,9.782],[-4.8,10],[4.8,10],[6.908,9.782],[7.782,8.908],[8,6.8],[8,-6.8],[7.782,-8.908],[6.908,-9.782],[4.8,-10],[-4.8,-10],[-6.908,-9.782]],"c":true}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[100]},{"t":30,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Rectangle 21","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-120,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_web_chrome.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"chrome_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector 20","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-38.383,-12.48,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[-100,-100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[5,0],[-5,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[5,0],[-5.252,2.02]],"c":false}]},{"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[5,0],[-5,0]],"c":false}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1.66,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":60,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Vector 20","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector 20","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[8.383,39.481,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[-100,-100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[5,0],[-5,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[5,0],[-5.879,2.144]],"c":false}]},{"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[5,0],[-5,0]],"c":false}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1.66,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":-60,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Vector 20","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Vector 20","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,-27,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[5,0],[-5,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[5,0],[-5.333,2]],"c":false}]},{"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[5,0],[-5,0]],"c":false}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1.66,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Vector 20","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Ellipse 18","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":0,"s":[9,9]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[5,5]},{"t":20,"s":[9,9]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1.66,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Обводка 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Ellipse 18","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Ellipse 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[-245]},{"t":30,"s":[-240]}],"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Ellipse 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_web_edge.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"edge_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Union","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.003,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-0.082,0.078],[-0.014,0.019],[0,0.42],[0.001,0.035],[0,0],[0,0],[0,0.009],[0.002,0.03],[0.293,0.391],[0.348,0.176],[0.39,0.003],[0.247,-0.117],[0,0],[0,0],[0.009,-0.004],[0.226,-0.375],[0.005,-0.438],[-3.697,0],[-0.897,0.336],[-0.267,0.139],[-0.069,-0.011],[-0.048,-0.051],[-0.007,-0.069],[0.037,-0.059],[2.152,-0.744],[0,0],[0.253,-0.054],[-0.228,0.072],[2.252,0.966],[1.04,2.219],[-0.014,1.51],[-0.03,0.216],[0.003,-0.209],[-1.868,1.842],[-2.628,0],[-1.655,-3.238],[-0.012,-0.024],[-0.003,-0.006],[0.019,-1.66],[0.417,-0.725],[0.722,-0.422],[0.832,-0.002],[0.001,0],[1.105,0.768],[0,0.204]],"o":[[0.024,-0.023],[0.395,-0.514],[0,-0.029],[0,0],[0,0],[0,-0.009],[-0.001,-0.027],[-0.029,-0.486],[-0.233,-0.313],[-0.348,-0.176],[-0.533,-0.01],[0,0],[0,0],[-0.009,0.004],[-0.384,0.209],[-0.226,0.375],[0,3.263],[0.958,0.002],[0.282,-0.106],[0.061,-0.034],[0.069,0.011],[0.048,0.051],[0.007,0.069],[-1.215,1.926],[0,0],[-0.193,0.061],[0.234,-0.044],[-2.325,0.775],[-2.252,-0.966],[-0.636,-1.37],[0,-0.213],[-0.033,0.203],[0.041,-2.622],[1.871,-1.845],[3.886,0],[0.011,0.022],[0.003,0.006],[0.283,0.552],[-0.002,0.836],[-0.417,0.725],[-0.716,0.425],[0,0],[-0.073,0.003],[-0.236,-0.165],[0,-0.191]],"v":[[1.84,1.691],[1.9,1.628],[2.509,0.073],[2.508,-0.023],[2.508,-0.022],[2.508,-0.021],[2.507,-0.048],[2.504,-0.134],[2.011,-1.479],[1.127,-2.223],[0.004,-2.495],[-1.181,-2.196],[-1.181,-2.196],[-1.183,-2.195],[-1.21,-2.182],[-2.142,-1.29],[-2.493,-0.049],[4.423,5.757],[7.228,5.252],[8.051,4.885],[8.251,4.849],[8.43,4.943],[8.514,5.128],[8.467,5.325],[3.264,9.45],[3.162,9.484],[2.478,9.66],[3.171,9.487],[-3.935,9.19],[-9.045,4.245],[-9.991,-0.13],[-9.945,-0.774],[-10,-0.156],[-7.022,-7.122],[-0.001,-10.001],[9.114,-4.9],[9.149,-4.832],[9.157,-4.815],[10,-1.47],[9.361,0.912],[7.622,2.661],[5.258,3.314],[5.256,3.314],[2.011,2.635],[1.642,2.071]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":40,"s":[{"i":[[-0.082,0.078],[-0.014,0.019],[0,0.42],[0.001,0.035],[0,0],[0,0],[0,0.009],[0.002,0.03],[0.293,0.391],[0.348,0.176],[0.39,0.003],[0.247,-0.117],[0,0],[0,0],[0.009,-0.004],[0.226,-0.375],[0.005,-0.438],[-3.279,0.493],[-0.897,0.336],[-0.267,0.139],[-0.069,-0.011],[-0.048,-0.051],[-0.007,-0.069],[0.037,-0.059],[2.152,-0.744],[0,0],[0.253,-0.054],[-0.228,0.072],[2.252,0.966],[1.04,2.219],[-0.014,1.51],[-0.03,0.216],[0.003,-0.209],[-1.868,1.842],[-2.628,0],[-1.655,-3.238],[-0.012,-0.024],[-0.003,-0.006],[0.019,-1.66],[0.417,-0.725],[0.722,-0.422],[0.832,-0.002],[0.001,0],[1.105,0.768],[0,0.204]],"o":[[0.024,-0.023],[0.395,-0.514],[0,-0.029],[0,0],[0,0],[0,-0.009],[-0.001,-0.027],[-0.029,-0.486],[-0.233,-0.313],[-0.348,-0.176],[-0.533,-0.01],[0,0],[0,0],[-0.009,0.004],[-0.384,0.209],[-0.226,0.375],[0,3.263],[1.152,-0.173],[0.282,-0.106],[0.061,-0.034],[0.069,0.011],[0.048,0.051],[0.007,0.069],[-1.215,1.926],[0,0],[-0.193,0.061],[0.234,-0.044],[-2.325,0.775],[-2.252,-0.966],[-0.636,-1.37],[0,-0.213],[-0.033,0.203],[0.041,-2.622],[1.871,-1.845],[3.886,0],[0.011,0.022],[0.003,0.006],[0.283,0.552],[-0.002,0.836],[-0.417,0.725],[-0.716,0.425],[0,0],[-0.073,0.003],[-0.236,-0.165],[0,-0.191]],"v":[[1.319,2.836],[1.379,2.774],[2.509,0.073],[2.508,-0.023],[2.508,-0.022],[2.508,-0.021],[2.507,-0.048],[2.504,-0.134],[2.011,-1.479],[1.127,-2.223],[0.004,-2.495],[-1.181,-2.196],[-1.181,-2.196],[-1.183,-2.195],[-1.21,-2.182],[-2.142,-1.29],[-2.493,-0.049],[4.423,5.757],[6.189,5.293],[7.114,4.78],[7.313,4.745],[7.493,4.839],[7.577,5.024],[7.529,5.221],[3.264,9.45],[3.162,9.484],[2.478,9.66],[3.171,9.487],[-3.935,9.19],[-9.045,4.245],[-9.991,-0.13],[-9.945,-0.774],[-10,-0.156],[-7.022,-7.122],[-0.001,-10.001],[9.114,-4.9],[9.149,-4.832],[9.157,-4.815],[10,-1.47],[8.84,2.058],[7.102,3.807],[4.737,4.459],[4.735,4.459],[1.49,3.781],[1.121,3.216]],"c":true}]},{"t":50,"s":[{"i":[[-0.082,0.078],[-0.014,0.019],[0,0.42],[0.001,0.035],[0,0],[0,0],[0,0.009],[0.002,0.03],[0.293,0.391],[0.348,0.176],[0.39,0.003],[0.247,-0.117],[0,0],[0,0],[0.009,-0.004],[0.226,-0.375],[0.005,-0.438],[-3.697,0],[-0.897,0.336],[-0.267,0.139],[-0.069,-0.011],[-0.048,-0.051],[-0.007,-0.069],[0.037,-0.059],[2.152,-0.744],[0,0],[0.253,-0.054],[-0.228,0.072],[2.252,0.966],[1.04,2.219],[-0.014,1.51],[-0.03,0.216],[0.003,-0.209],[-1.868,1.842],[-2.628,0],[-1.655,-3.238],[-0.012,-0.024],[-0.003,-0.006],[0.019,-1.66],[0.417,-0.725],[0.722,-0.422],[0.832,-0.002],[0.001,0],[1.105,0.768],[0,0.204]],"o":[[0.024,-0.023],[0.395,-0.514],[0,-0.029],[0,0],[0,0],[0,-0.009],[-0.001,-0.027],[-0.029,-0.486],[-0.233,-0.313],[-0.348,-0.176],[-0.533,-0.01],[0,0],[0,0],[-0.009,0.004],[-0.384,0.209],[-0.226,0.375],[0,3.263],[0.958,0.002],[0.282,-0.106],[0.061,-0.034],[0.069,0.011],[0.048,0.051],[0.007,0.069],[-1.215,1.926],[0,0],[-0.193,0.061],[0.234,-0.044],[-2.325,0.775],[-2.252,-0.966],[-0.636,-1.37],[0,-0.213],[-0.033,0.203],[0.041,-2.622],[1.871,-1.845],[3.886,0],[0.011,0.022],[0.003,0.006],[0.283,0.552],[-0.002,0.836],[-0.417,0.725],[-0.716,0.425],[0,0],[-0.073,0.003],[-0.236,-0.165],[0,-0.191]],"v":[[1.84,1.691],[1.9,1.628],[2.509,0.073],[2.508,-0.023],[2.508,-0.022],[2.508,-0.021],[2.507,-0.048],[2.504,-0.134],[2.011,-1.479],[1.127,-2.223],[0.004,-2.495],[-1.181,-2.196],[-1.181,-2.196],[-1.183,-2.195],[-1.21,-2.182],[-2.142,-1.29],[-2.493,-0.049],[4.423,5.757],[7.228,5.252],[8.051,4.885],[8.251,4.849],[8.43,4.943],[8.514,5.128],[8.467,5.325],[3.264,9.45],[3.162,9.484],[2.478,9.66],[3.171,9.487],[-3.935,9.19],[-9.045,4.245],[-9.991,-0.13],[-9.945,-0.774],[-10,-0.156],[-7.022,-7.122],[-0.001,-10.001],[9.114,-4.9],[9.149,-4.832],[9.157,-4.815],[10,-1.47],[9.361,0.912],[7.622,2.661],[5.258,3.314],[5.256,3.314],[2.011,2.635],[1.642,2.071]],"c":true}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.005]],"o":[[0,-0.005],[0,0]],"v":[[-10,-0.142],[-10,-0.156]],"c":false},"ix":2},"nm":"Контур 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Объединить контуры 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Union","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Ellipse 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":40,"s":[1090]},{"t":50,"s":[1080]}],"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[11.667,11.667,100]},{"t":40,"s":[16.667,16.667,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":120,"st":-60,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_web_firefox.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"firefox_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.974,-1.629,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[-0.03,-0.196],[0.001,-0.315],[0,-0.044],[0.784,-1.26],[0.037,-0.059],[0.129,-0.308],[0.711,-0.509],[0.55,-0.259],[0,0],[0,0],[0.07,-0.029],[0.18,-0.163],[3.652,0],[0.988,0.296],[-0.036,-0.014],[0.11,0.04],[0.723,0.489],[0.845,1.898],[-0.075,1.505],[0.08,-0.373],[-0.467,1.186],[0.175,-0.384],[-0.528,0.892],[-0.21,0.229],[0,0],[-0.018,0.121],[-0.293,0.65],[0,0],[0,-0.031],[-0.004,0.014],[-0.041,0.083],[-0.067,0.076],[-0.005,0.007],[0.006,-0.047],[0,0.004],[-0.041,0.093],[-0.224,0.154],[0,0],[-0.14,-0.364],[0,0],[-0.016,0],[0,-0.005],[-0.039,-0.068],[-0.052,-0.077],[0,0],[0,0],[-0.157,-0.134],[0,0],[-0.764,-0.289],[-0.118,0.088],[0.005,-0.039],[-0.257,0.109],[-0.001,-0.033],[-0.368,0.071],[0.068,-0.058],[-0.176,0.009],[0.062,-0.026],[0.117,-0.057],[0.035,-0.028],[0.261,-0.684],[0,0],[0,0],[-0.485,-0.077],[-0.041,-0.152],[0,0],[0.006,-0.04],[0.233,-0.198],[0.07,-0.045],[0.28,-0.123],[0.316,-0.196],[0.045,-0.044],[0,-0.005],[-0.011,-0.056],[-0.036,-0.068],[0.009,-0.115],[0.083,-0.192],[0.101,0.051],[0,0],[-0.046,-0.118],[0,0],[0.09,0.05],[0.113,0.049],[0.012,-0.004],[0,0],[0.129,0.064],[0.093,-0.166],[-0.179,-0.324],[-0.259,-0.177],[-0.015,-0.012],[-0.218,-0.109],[-0.068,-0.039],[-0.064,-0.034],[-0.763,0.111],[-0.451,-0.592],[0.366,0.116],[0,0],[0.762,-0.423],[0.818,0.173],[0.199,0.069],[0,0],[0,0],[-0.562,-0.34],[-0.416,-0.078],[-1.148,0.914],[-0.001,1.467],[0.272,0.642],[-0.488,-0.931],[1.067,0.88],[0.381,1.005],[0,0],[-1.363,-1.273],[-0.526,-0.531],[-0.141,0.387],[-0.334,-0.559],[-0.386,-0.63],[-0.079,-0.119],[-0.165,-0.347],[-0.16,-0.563],[-0.039,-0.466]],"o":[[0,0],[0.055,0.31],[0,0.04],[-0.062,1.483],[-0.04,0.067],[0.117,0.313],[-0.218,0.847],[-0.474,0.382],[0,0],[0,0],[-0.072,0.033],[-0.104,0.22],[-0.111,0.139],[-1.032,-0.001],[0.036,0.016],[-0.114,-0.038],[-0.834,-0.257],[-1.778,-1.076],[-0.63,-1.369],[-0.123,0.361],[0,-1.275],[-0.241,0.346],[0.247,-1.007],[0.158,-0.267],[0,0],[-0.004,-0.122],[0.065,-0.71],[0,0],[0.006,-0.012],[0,0.031],[0.026,-0.089],[0.045,-0.091],[0.005,-0.007],[0.005,-0.007],[0,0.017],[0.027,-0.051],[0.09,-0.257],[0,0],[-0.013,0.39],[0,0],[0.014,0.02],[0.003,0.001],[0.04,0.082],[0.055,0.097],[0,0],[0,0],[0.115,0.18],[0,0],[0.797,-0.161],[0.095,-0.112],[0,0.039],[0.171,-0.221],[-0.014,0.03],[0.323,-0.19],[0.048,0],[0.162,-0.07],[0.288,-0.03],[-0.122,0.044],[-0.035,0.029],[-0.613,0.401],[0,0],[0,0],[0.108,0.479],[1.373,0.129],[0,0],[-0.002,0.04],[-0.056,0.301],[-0.062,0.056],[-0.047,0.027],[-0.344,0.141],[-0.053,0.035],[-0.016,0.017],[0.025,0.051],[-0.063,-0.071],[0.04,0.108],[0.007,0.209],[-0.091,-0.068],[0,0],[0.106,0.069],[0.034,0.095],[-0.059,-0.084],[-0.132,-0.078],[-0.012,0.007],[0.032,0.057],[0,0],[-0.171,0.083],[-0.151,0.338],[0.174,0.261],[0.016,0.012],[0.2,0.14],[0.066,0.044],[0.061,0.04],[1,0.525],[0.733,-0.129],[0.261,0.371],[0,0],[-0.374,-0.124],[-0.755,0.359],[-0.207,-0.04],[0,0],[0,0],[0.383,0.533],[0.377,0.192],[1.431,0.327],[1.148,-0.914],[0.004,-0.698],[0.904,0.537],[-0.606,-1.77],[-0.858,-0.646],[-1.103,-2.96],[0,0],[0.276,0.257],[0.074,-0.405],[0.11,0.642],[0.512,0.728],[0.083,0.112],[0.221,0.314],[0.262,0.523],[0.128,0.45],[0.127,-0.167]],"v":[[10.333,-1.238],[10.393,-0.927],[10.475,0.011],[10.475,0.135],[9.184,4.32],[9.068,4.509],[9.048,5.476],[7.611,7.575],[6.069,8.54],[5.987,8.579],[5.942,8.599],[5.729,8.692],[5.298,9.271],[0.329,10.801],[-2.718,10.353],[-2.614,10.398],[-2.948,10.281],[-5.296,9.156],[-9.325,4.587],[-10.17,0.211],[-10.475,1.314],[-9.767,-2.41],[-10.394,-1.312],[-9.224,-4.176],[-8.671,-4.921],[-8.671,-4.932],[-8.65,-5.296],[-8.109,-7.351],[-8.094,-7.38],[-8.094,-7.305],[-8.094,-7.261],[-7.992,-7.52],[-7.822,-7.772],[-7.809,-7.791],[-7.831,-7.656],[-7.831,-7.632],[-7.736,-7.827],[-7.253,-8.459],[-7.242,-8.464],[-7.05,-7.322],[-7.05,-7.318],[-7.009,-7.374],[-7,-7.366],[-6.881,-7.137],[-6.721,-6.875],[-6.708,-6.86],[-6.697,-6.863],[-6.282,-6.389],[-6.275,-6.383],[-3.888,-6.184],[-3.568,-6.485],[-3.575,-6.367],[-2.922,-6.871],[-2.942,-6.776],[-1.898,-7.171],[-2.121,-7.035],[-1.609,-7.156],[-1.058,-7.036],[-1.416,-6.884],[-1.311,-6.863],[-2.655,-5.193],[-2.655,-5.182],[-2.655,-5.188],[-1.674,-4.268],[0.003,-3.872],[0.003,-3.801],[-0.009,-3.681],[-0.456,-2.909],[-0.654,-2.756],[-1.214,-2.513],[-2.206,-2.008],[-2.352,-1.889],[-2.404,-1.82],[-2.351,-1.658],[-2.434,-1.635],[-2.387,-1.296],[-2.502,-0.687],[-2.791,-0.866],[-2.802,-0.866],[-2.567,-0.579],[-2.579,-0.462],[-2.806,-0.665],[-3.301,-0.919],[-3.334,-0.912],[-3.244,-0.746],[-3.453,-0.858],[-3.859,-0.476],[-3.814,0.576],[-3.159,1.239],[-3.294,1.203],[-2.666,1.578],[-2.815,1.564],[-2.628,1.674],[-0.165,1.546],[1.763,2.299],[1.37,2.908],[1.363,2.908],[-0.235,3.521],[-2.661,3.807],[-3.27,3.644],[-3.355,3.613],[-3.349,3.624],[-1.917,4.948],[-0.722,5.354],[3.358,4.425],[5.176,0.656],[4.77,-1.375],[6.898,0.87],[4.076,-2.472],[2.181,-4.999],[3.623,-10.801],[4.828,-8.868],[6.088,-7.703],[6.41,-8.892],[7.081,-7.074],[8.422,-5.33],[8.665,-4.985],[9.245,-3.991],[9.879,-2.359],[10.13,-0.982]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[{"i":[[0,0],[-0.03,-0.196],[0.001,-0.315],[0,-0.044],[0.784,-1.26],[0.037,-0.059],[0.129,-0.308],[0.711,-0.509],[0.55,-0.259],[0,0],[0,0],[0.07,-0.029],[0.18,-0.163],[3.652,0],[0.988,0.296],[-0.036,-0.014],[0.11,0.04],[0.723,0.489],[0.845,1.898],[-0.075,1.505],[0.08,-0.373],[-0.467,1.186],[0.175,-0.384],[-0.528,0.892],[-0.21,0.229],[0,0],[-0.018,0.121],[-0.293,0.65],[0,0],[0,-0.031],[-0.004,0.014],[-0.041,0.083],[-0.067,0.076],[-0.005,0.007],[0.006,-0.047],[0,0.004],[-0.041,0.093],[-0.224,0.154],[0,0],[-0.14,-0.364],[0,0],[-0.016,0],[0,-0.005],[-0.039,-0.068],[-0.052,-0.077],[0,0],[0,0],[-0.157,-0.134],[0,0],[-0.764,-0.289],[-0.118,0.088],[0.005,-0.039],[-0.257,0.109],[-0.001,-0.033],[-0.368,0.071],[0.068,-0.058],[-0.176,0.009],[0.062,-0.026],[0.117,-0.057],[0.035,-0.028],[0.261,-0.684],[0,0],[0,0],[-0.485,-0.077],[-0.041,-0.152],[0,0],[0.006,-0.04],[0.233,-0.198],[0.07,-0.045],[0.28,-0.123],[0.316,-0.196],[0.045,-0.044],[0,-0.005],[-0.011,-0.056],[-0.036,-0.068],[0.009,-0.115],[0.083,-0.192],[0.101,0.051],[0,0],[-0.046,-0.118],[0,0],[0.09,0.05],[0.113,0.049],[0.012,-0.004],[0,0],[0.129,0.064],[0.093,-0.166],[-0.179,-0.324],[-0.259,-0.177],[-0.015,-0.012],[-0.218,-0.109],[-0.068,-0.039],[-0.017,-0.071],[-0.427,-0.474],[-0.451,-0.592],[0.366,0.116],[0,0],[0.762,-0.423],[0.818,0.173],[0.199,0.069],[0,0],[0,0],[-0.562,-0.34],[-0.416,-0.078],[-1.148,0.914],[-0.001,1.467],[0.272,0.642],[-0.488,-0.931],[1.067,0.88],[0.381,1.005],[0,0],[0.043,-1.277],[-0.03,-0.651],[-0.141,0.387],[-0.334,-0.559],[-0.386,-0.63],[-0.079,-0.119],[-0.165,-0.347],[-0.16,-0.563],[-0.039,-0.466]],"o":[[0,0],[0.055,0.31],[0,0.04],[-0.062,1.483],[-0.04,0.067],[0.117,0.313],[-0.218,0.847],[-0.474,0.382],[0,0],[0,0],[-0.072,0.033],[-0.104,0.22],[-0.111,0.139],[-1.032,-0.001],[0.036,0.016],[-0.114,-0.038],[-0.834,-0.257],[-1.778,-1.076],[-0.63,-1.369],[-0.123,0.361],[0,-1.275],[-0.241,0.346],[0.247,-1.007],[0.158,-0.267],[0,0],[-0.004,-0.122],[0.065,-0.71],[0,0],[0.006,-0.012],[0,0.031],[0.026,-0.089],[0.045,-0.091],[0.005,-0.007],[0.005,-0.007],[0,0.017],[0.027,-0.051],[0.09,-0.257],[0,0],[-0.013,0.39],[0,0],[0.014,0.02],[0.003,0.001],[0.04,0.082],[0.055,0.097],[0,0],[0,0],[0.115,0.18],[0,0],[0.797,-0.161],[0.095,-0.112],[0,0.039],[0.171,-0.221],[-0.014,0.03],[0.323,-0.19],[0.048,0],[0.162,-0.07],[0.288,-0.03],[-0.122,0.044],[-0.035,0.029],[-0.613,0.401],[0,0],[0,0],[0.108,0.479],[1.373,0.129],[0,0],[-0.002,0.04],[-0.056,0.301],[-0.062,0.056],[-0.047,0.027],[-0.344,0.141],[-0.053,0.035],[-0.016,0.017],[0.025,0.051],[-0.063,-0.071],[0.04,0.108],[0.007,0.209],[-0.091,-0.068],[0,0],[0.106,0.069],[0.034,0.095],[-0.059,-0.084],[-0.132,-0.078],[-0.012,0.007],[0.032,0.057],[0,0],[-0.171,0.083],[-0.151,0.338],[0.174,0.261],[0.016,0.012],[0.2,0.14],[0.066,0.044],[0.061,0.04],[0.332,1.348],[0.786,0.559],[0.261,0.371],[0,0],[-0.374,-0.124],[-0.603,-0.499],[-0.344,-0.557],[0,0],[0,0],[0.383,0.533],[0.377,0.192],[1.431,0.327],[1.148,-0.914],[0.004,-0.698],[0.904,0.537],[-0.606,-1.77],[-0.858,-0.646],[-1.103,-2.96],[0,0],[0.293,0.889],[0.074,-0.405],[0.11,0.642],[0.512,0.728],[0.083,0.112],[0.221,0.314],[0.262,0.523],[0.128,0.45],[0.127,-0.167]],"v":[[10.333,-1.238],[10.393,-0.927],[10.475,0.011],[10.475,0.135],[9.184,4.32],[9.068,4.509],[9.048,5.476],[7.611,7.575],[6.069,8.54],[5.987,8.579],[5.942,8.599],[5.729,8.692],[5.298,9.271],[0.329,10.801],[-2.718,10.353],[-2.614,10.398],[-2.948,10.281],[-5.296,9.156],[-9.325,4.587],[-10.17,0.211],[-10.162,1.314],[-9.767,-2.41],[-10.185,-1.312],[-9.224,-4.176],[-8.671,-4.921],[-8.671,-4.932],[-8.65,-5.296],[-8.109,-6.934],[-8.094,-6.963],[-8.094,-6.888],[-8.094,-6.845],[-7.992,-7.103],[-7.822,-7.355],[-7.809,-7.375],[-7.831,-7.239],[-7.831,-7.216],[-7.736,-7.41],[-7.253,-8.042],[-7.242,-8.048],[-7.05,-6.906],[-7.05,-6.901],[-7.009,-6.957],[-7,-6.949],[-6.881,-6.72],[-6.721,-6.458],[-6.708,-6.443],[-6.697,-6.446],[-6.282,-6.389],[-6.275,-6.383],[-3.888,-6.184],[-3.568,-6.485],[-3.575,-6.367],[-2.922,-6.662],[-2.942,-6.568],[-1.898,-6.676],[-2.121,-6.54],[-1.609,-6.661],[-1.058,-6.541],[-1.416,-6.389],[-1.311,-6.368],[-2.655,-5.193],[-2.655,-5.182],[-2.655,-5.188],[-1.674,-4.268],[-0.31,-3.872],[-0.31,-3.801],[-0.321,-3.681],[-0.768,-2.909],[-0.967,-2.756],[-1.526,-2.513],[-2.206,-2.008],[-2.352,-1.889],[-2.404,-1.82],[-2.351,-1.658],[-2.434,-1.635],[-2.387,-1.296],[-1.761,-0.752],[-2.049,-0.931],[-2.06,-0.931],[-1.826,-0.644],[-1.838,-0.527],[-2.064,-0.73],[-1.967,-1.036],[-2,-1.028],[-1.909,-0.863],[-2.119,-0.975],[-2.525,-0.593],[-2.48,0.459],[-2.346,1.122],[-2.481,1.087],[-2.135,1.462],[-2.284,1.447],[-2.097,1.557],[-1.721,2.102],[-0.49,2.763],[-0.883,3.372],[-0.889,3.372],[-1.895,2.891],[-2.101,2.604],[-2.066,2.045],[-2.151,2.014],[-2.144,2.025],[-1.357,2.808],[-0.162,3.214],[2.435,2.414],[3.385,0.876],[2.979,-1.155],[4.378,1.091],[2.001,-2.291],[2.181,-4.999],[4.248,-10.801],[5.453,-8.868],[5.359,-7.703],[5.264,-8.892],[7.081,-7.074],[8.422,-5.33],[8.665,-4.985],[9.245,-3.991],[9.879,-2.359],[10.13,-0.982]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":37,"s":[{"i":[[0,0],[-0.03,-0.196],[0.001,-0.315],[0,-0.044],[0.784,-1.26],[0.037,-0.059],[0.129,-0.308],[0.711,-0.509],[0.55,-0.259],[0,0],[0,0],[0.07,-0.029],[0.18,-0.163],[3.652,0],[0.988,0.296],[-0.036,-0.014],[0.11,0.04],[0.723,0.489],[0.845,1.898],[-0.075,1.505],[0.08,-0.373],[-0.467,1.186],[0.175,-0.384],[-0.528,0.892],[-0.21,0.229],[0,0],[-0.018,0.121],[-0.293,0.65],[0,0],[0,-0.031],[-0.004,0.014],[-0.041,0.083],[-0.067,0.076],[-0.005,0.007],[0.006,-0.047],[0,0.004],[-0.041,0.093],[-0.224,0.154],[0,0],[-0.14,-0.364],[0,0],[-0.016,0],[0,-0.005],[-0.039,-0.068],[-0.052,-0.077],[0,0],[0,0],[-0.157,-0.134],[0,0],[-0.764,-0.289],[-0.118,0.088],[0.005,-0.039],[-0.257,0.109],[-0.001,-0.033],[-0.368,0.071],[0.068,-0.058],[-0.176,0.009],[0.062,-0.026],[0.117,-0.057],[0.035,-0.028],[0.261,-0.684],[0,0],[0,0],[-0.485,-0.077],[-0.041,-0.152],[0,0],[0.006,-0.04],[0.233,-0.198],[0.07,-0.045],[0.28,-0.123],[0.316,-0.196],[0.045,-0.044],[0,-0.005],[-0.011,-0.056],[-0.036,-0.068],[0.009,-0.115],[0.083,-0.192],[0.101,0.051],[0,0],[-0.046,-0.118],[0,0],[0.09,0.05],[0.113,0.049],[0.012,-0.004],[0,0],[0.129,0.064],[0.093,-0.166],[-0.179,-0.324],[-0.259,-0.177],[-0.015,-0.012],[-0.218,-0.109],[-0.068,-0.039],[-0.017,-0.071],[-0.427,-0.474],[-0.451,-0.592],[0.366,0.116],[0,0],[0.762,-0.423],[0.818,0.173],[0.199,0.069],[0,0],[0,0],[-0.562,-0.34],[-0.416,-0.078],[-1.148,0.914],[-0.001,1.467],[0.272,0.642],[-0.488,-0.931],[1.067,0.88],[0.381,1.005],[0,0],[0.043,-1.277],[-0.03,-0.651],[-0.141,0.387],[-0.334,-0.559],[-0.386,-0.63],[-0.079,-0.119],[-0.165,-0.347],[-0.16,-0.563],[-0.039,-0.466]],"o":[[0,0],[0.055,0.31],[0,0.04],[-0.062,1.483],[-0.04,0.067],[0.117,0.313],[-0.218,0.847],[-0.474,0.382],[0,0],[0,0],[-0.072,0.033],[-0.104,0.22],[-0.111,0.139],[-1.032,-0.001],[0.036,0.016],[-0.114,-0.038],[-0.834,-0.257],[-1.778,-1.076],[-0.63,-1.369],[-0.123,0.361],[0,-1.275],[-0.241,0.346],[0.247,-1.007],[0.158,-0.267],[0,0],[-0.004,-0.122],[0.065,-0.71],[0,0],[0.006,-0.012],[0,0.031],[0.026,-0.089],[0.045,-0.091],[0.005,-0.007],[0.005,-0.007],[0,0.017],[0.027,-0.051],[0.09,-0.257],[0,0],[-0.013,0.39],[0,0],[0.014,0.02],[0.003,0.001],[0.04,0.082],[0.055,0.097],[0,0],[0,0],[0.115,0.18],[0,0],[0.797,-0.161],[0.095,-0.112],[0,0.039],[0.171,-0.221],[-0.014,0.03],[0.323,-0.19],[0.048,0],[0.162,-0.07],[0.288,-0.03],[-0.122,0.044],[-0.035,0.029],[-0.613,0.401],[0,0],[0,0],[0.108,0.479],[1.373,0.129],[0,0],[-0.002,0.04],[-0.056,0.301],[-0.062,0.056],[-0.047,0.027],[-0.344,0.141],[-0.053,0.035],[-0.016,0.017],[0.025,0.051],[-0.063,-0.071],[0.04,0.108],[0.007,0.209],[-0.091,-0.068],[0,0],[0.106,0.069],[0.034,0.095],[-0.059,-0.084],[-0.132,-0.078],[-0.012,0.007],[0.032,0.057],[0,0],[-0.171,0.083],[-0.151,0.338],[0.174,0.261],[0.016,0.012],[0.2,0.14],[0.066,0.044],[0.061,0.04],[0.332,1.348],[0.786,0.559],[0.261,0.371],[0,0],[-0.374,-0.124],[-0.603,-0.499],[-0.344,-0.557],[0,0],[0,0],[0.383,0.533],[0.377,0.192],[1.431,0.327],[1.148,-0.914],[0.004,-0.698],[0.904,0.537],[-0.606,-1.77],[-0.858,-0.646],[-1.103,-2.96],[0,0],[0.293,0.889],[0.074,-0.405],[0.11,0.642],[0.512,0.728],[0.083,0.112],[0.221,0.314],[0.262,0.523],[0.128,0.45],[0.127,-0.167]],"v":[[10.333,-1.238],[10.393,-0.927],[10.475,0.011],[10.475,0.135],[9.184,4.32],[9.068,4.509],[9.048,5.476],[7.611,7.575],[6.069,8.54],[5.987,8.579],[5.942,8.599],[5.729,8.692],[5.298,9.271],[0.329,10.801],[-2.718,10.353],[-2.614,10.398],[-2.948,10.281],[-5.296,9.156],[-9.325,4.587],[-10.17,0.211],[-10.162,1.314],[-9.767,-2.41],[-10.185,-1.312],[-9.224,-4.176],[-8.671,-4.921],[-8.671,-4.932],[-8.65,-5.296],[-8.109,-6.934],[-8.094,-6.963],[-8.094,-6.888],[-8.094,-6.845],[-7.992,-7.103],[-7.822,-7.355],[-7.809,-7.375],[-7.831,-7.239],[-7.831,-7.216],[-7.736,-7.41],[-7.253,-8.042],[-7.242,-8.048],[-7.05,-6.906],[-7.05,-6.901],[-7.009,-6.957],[-7,-6.949],[-6.881,-6.72],[-6.721,-6.458],[-6.708,-6.443],[-6.697,-6.446],[-6.282,-6.389],[-6.275,-6.383],[-3.888,-6.184],[-3.568,-6.485],[-3.575,-6.367],[-2.922,-6.662],[-2.942,-6.568],[-1.898,-6.676],[-2.121,-6.54],[-1.609,-6.661],[-1.058,-6.541],[-1.416,-6.389],[-1.311,-6.368],[-2.655,-5.193],[-2.655,-5.182],[-2.655,-5.188],[-1.674,-4.268],[-0.31,-3.872],[-0.31,-3.801],[-0.321,-3.681],[-0.768,-2.909],[-0.967,-2.756],[-1.526,-2.513],[-2.206,-2.008],[-2.352,-1.889],[-2.404,-1.82],[-2.351,-1.658],[-2.434,-1.635],[-2.387,-1.296],[-1.761,-0.752],[-2.049,-0.931],[-2.06,-0.931],[-1.826,-0.644],[-1.838,-0.527],[-2.064,-0.73],[-1.967,-1.036],[-2,-1.028],[-1.909,-0.863],[-2.119,-0.975],[-2.525,-0.593],[-2.48,0.459],[-2.346,1.122],[-2.481,1.087],[-2.135,1.462],[-2.284,1.447],[-2.097,1.557],[-1.721,2.102],[-0.49,2.763],[-0.883,3.372],[-0.889,3.372],[-1.895,2.891],[-2.101,2.604],[-2.066,2.045],[-2.151,2.014],[-2.144,2.025],[-1.357,2.808],[-0.162,3.214],[2.435,2.414],[3.385,0.876],[2.979,-1.155],[4.378,1.091],[2.001,-2.291],[2.181,-4.999],[4.248,-10.801],[5.453,-8.868],[5.359,-7.703],[5.264,-8.892],[7.081,-7.074],[8.422,-5.33],[8.665,-4.985],[9.245,-3.991],[9.879,-2.359],[10.13,-0.982]],"c":true}]},{"t":60,"s":[{"i":[[0,0],[-0.03,-0.196],[0.001,-0.315],[0,-0.044],[0.784,-1.26],[0.037,-0.059],[0.129,-0.308],[0.711,-0.509],[0.55,-0.259],[0,0],[0,0],[0.07,-0.029],[0.18,-0.163],[3.652,0],[0.988,0.296],[-0.036,-0.014],[0.11,0.04],[0.723,0.489],[0.845,1.898],[-0.075,1.505],[0.08,-0.373],[-0.467,1.186],[0.175,-0.384],[-0.528,0.892],[-0.21,0.229],[0,0],[-0.018,0.121],[-0.293,0.65],[0,0],[0,-0.031],[-0.004,0.014],[-0.041,0.083],[-0.067,0.076],[-0.005,0.007],[0.006,-0.047],[0,0.004],[-0.041,0.093],[-0.224,0.154],[0,0],[-0.14,-0.364],[0,0],[-0.016,0],[0,-0.005],[-0.039,-0.068],[-0.052,-0.077],[0,0],[0,0],[-0.157,-0.134],[0,0],[-0.764,-0.289],[-0.118,0.088],[0.005,-0.039],[-0.257,0.109],[-0.001,-0.033],[-0.368,0.071],[0.068,-0.058],[-0.176,0.009],[0.062,-0.026],[0.117,-0.057],[0.035,-0.028],[0.261,-0.684],[0,0],[0,0],[-0.485,-0.077],[-0.041,-0.152],[0,0],[0.006,-0.04],[0.233,-0.198],[0.07,-0.045],[0.28,-0.123],[0.316,-0.196],[0.045,-0.044],[0,-0.005],[-0.011,-0.056],[-0.036,-0.068],[0.009,-0.115],[0.083,-0.192],[0.101,0.051],[0,0],[-0.046,-0.118],[0,0],[0.09,0.05],[0.113,0.049],[0.012,-0.004],[0,0],[0.129,0.064],[0.093,-0.166],[-0.179,-0.324],[-0.259,-0.177],[-0.015,-0.012],[-0.218,-0.109],[-0.068,-0.039],[-0.064,-0.034],[-0.763,0.111],[-0.451,-0.592],[0.366,0.116],[0,0],[0.762,-0.423],[0.818,0.173],[0.199,0.069],[0,0],[0,0],[-0.562,-0.34],[-0.416,-0.078],[-1.148,0.914],[-0.001,1.467],[0.272,0.642],[-0.488,-0.931],[1.067,0.88],[0.381,1.005],[0,0],[-1.363,-1.273],[-0.526,-0.531],[-0.141,0.387],[-0.334,-0.559],[-0.386,-0.63],[-0.079,-0.119],[-0.165,-0.347],[-0.16,-0.563],[-0.039,-0.466]],"o":[[0,0],[0.055,0.31],[0,0.04],[-0.062,1.483],[-0.04,0.067],[0.117,0.313],[-0.218,0.847],[-0.474,0.382],[0,0],[0,0],[-0.072,0.033],[-0.104,0.22],[-0.111,0.139],[-1.032,-0.001],[0.036,0.016],[-0.114,-0.038],[-0.834,-0.257],[-1.778,-1.076],[-0.63,-1.369],[-0.123,0.361],[0,-1.275],[-0.241,0.346],[0.247,-1.007],[0.158,-0.267],[0,0],[-0.004,-0.122],[0.065,-0.71],[0,0],[0.006,-0.012],[0,0.031],[0.026,-0.089],[0.045,-0.091],[0.005,-0.007],[0.005,-0.007],[0,0.017],[0.027,-0.051],[0.09,-0.257],[0,0],[-0.013,0.39],[0,0],[0.014,0.02],[0.003,0.001],[0.04,0.082],[0.055,0.097],[0,0],[0,0],[0.115,0.18],[0,0],[0.797,-0.161],[0.095,-0.112],[0,0.039],[0.171,-0.221],[-0.014,0.03],[0.323,-0.19],[0.048,0],[0.162,-0.07],[0.288,-0.03],[-0.122,0.044],[-0.035,0.029],[-0.613,0.401],[0,0],[0,0],[0.108,0.479],[1.373,0.129],[0,0],[-0.002,0.04],[-0.056,0.301],[-0.062,0.056],[-0.047,0.027],[-0.344,0.141],[-0.053,0.035],[-0.016,0.017],[0.025,0.051],[-0.063,-0.071],[0.04,0.108],[0.007,0.209],[-0.091,-0.068],[0,0],[0.106,0.069],[0.034,0.095],[-0.059,-0.084],[-0.132,-0.078],[-0.012,0.007],[0.032,0.057],[0,0],[-0.171,0.083],[-0.151,0.338],[0.174,0.261],[0.016,0.012],[0.2,0.14],[0.066,0.044],[0.061,0.04],[1,0.525],[0.733,-0.129],[0.261,0.371],[0,0],[-0.374,-0.124],[-0.755,0.359],[-0.207,-0.04],[0,0],[0,0],[0.383,0.533],[0.377,0.192],[1.431,0.327],[1.148,-0.914],[0.004,-0.698],[0.904,0.537],[-0.606,-1.77],[-0.858,-0.646],[-1.103,-2.96],[0,0],[0.276,0.257],[0.074,-0.405],[0.11,0.642],[0.512,0.728],[0.083,0.112],[0.221,0.314],[0.262,0.523],[0.128,0.45],[0.127,-0.167]],"v":[[10.333,-1.238],[10.393,-0.927],[10.475,0.011],[10.475,0.135],[9.184,4.32],[9.068,4.509],[9.048,5.476],[7.611,7.575],[6.069,8.54],[5.987,8.579],[5.942,8.599],[5.729,8.692],[5.298,9.271],[0.329,10.801],[-2.718,10.353],[-2.614,10.398],[-2.948,10.281],[-5.296,9.156],[-9.325,4.587],[-10.17,0.211],[-10.475,1.314],[-9.767,-2.41],[-10.394,-1.312],[-9.224,-4.176],[-8.671,-4.921],[-8.671,-4.932],[-8.65,-5.296],[-8.109,-7.351],[-8.094,-7.38],[-8.094,-7.305],[-8.094,-7.261],[-7.992,-7.52],[-7.822,-7.772],[-7.809,-7.791],[-7.831,-7.656],[-7.831,-7.632],[-7.736,-7.827],[-7.253,-8.459],[-7.242,-8.464],[-7.05,-7.322],[-7.05,-7.318],[-7.009,-7.374],[-7,-7.366],[-6.881,-7.137],[-6.721,-6.875],[-6.708,-6.86],[-6.697,-6.863],[-6.282,-6.389],[-6.275,-6.383],[-3.888,-6.184],[-3.568,-6.485],[-3.575,-6.367],[-2.922,-6.871],[-2.942,-6.776],[-1.898,-7.171],[-2.121,-7.035],[-1.609,-7.156],[-1.058,-7.036],[-1.416,-6.884],[-1.311,-6.863],[-2.655,-5.193],[-2.655,-5.182],[-2.655,-5.188],[-1.674,-4.268],[0.003,-3.872],[0.003,-3.801],[-0.009,-3.681],[-0.456,-2.909],[-0.654,-2.756],[-1.214,-2.513],[-2.206,-2.008],[-2.352,-1.889],[-2.404,-1.82],[-2.351,-1.658],[-2.434,-1.635],[-2.387,-1.296],[-2.502,-0.687],[-2.791,-0.866],[-2.802,-0.866],[-2.567,-0.579],[-2.579,-0.462],[-2.806,-0.665],[-3.301,-0.919],[-3.334,-0.912],[-3.244,-0.746],[-3.453,-0.858],[-3.859,-0.476],[-3.814,0.576],[-3.159,1.239],[-3.294,1.203],[-2.666,1.578],[-2.815,1.564],[-2.628,1.674],[-0.165,1.546],[1.763,2.299],[1.37,2.908],[1.363,2.908],[-0.235,3.521],[-2.661,3.807],[-3.27,3.644],[-3.355,3.613],[-3.349,3.624],[-1.917,4.948],[-0.722,5.354],[3.358,4.425],[5.176,0.656],[4.77,-1.375],[6.898,0.87],[4.076,-2.472],[2.181,-4.999],[3.623,-10.801],[4.828,-8.868],[6.088,-7.703],[6.41,-8.892],[7.081,-7.074],[8.422,-5.33],[8.665,-4.985],[9.245,-3.991],[9.879,-2.359],[10.13,-0.982]],"c":true}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-0.02,0.05]],"o":[[0.018,-0.051],[0,0]],"v":[[-2.71,-5.03],[-2.655,-5.182]],"c":false},"ix":2},"nm":"Контур 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Объединить контуры 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Ellipse 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":40,"s":[1090]},{"t":50,"s":[1080]}],"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[16.667,16.667,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[11.667,11.667,100]},{"t":40,"s":[16.667,16.667,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":120,"st":-60,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/icons/settings/devices/device_web_safari.lottie ================================================ {"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"safari_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Com 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[185]},{"t":30,"s":[180]}],"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.15,0.205],[-0.233,0.543],[0,0],[0.142,0.444],[0.385,0.123],[1.435,-0.615],[0,0],[0.231,-0.17],[0.15,-0.205],[0.233,-0.543],[0,0],[-0.142,-0.444],[-0.385,-0.123],[-1.435,0.615],[0,0],[-0.231,0.17]],"o":[[0.17,-0.231],[0,0],[0.615,-1.435],[-0.123,-0.385],[-0.444,-0.142],[0,0],[-0.543,0.233],[-0.205,0.15],[-0.17,0.231],[0,0],[-0.615,1.435],[0.123,0.385],[0.444,0.142],[0,0],[0.543,-0.233],[0.205,-0.15]],"v":[[2.611,2.075],[3.13,1.029],[4.28,-1.654],[5.061,-4.251],[4.251,-5.061],[1.654,-4.28],[-1.029,-3.13],[-2.075,-2.611],[-2.611,-2.075],[-3.13,-1.029],[-4.28,1.654],[-5.061,4.251],[-4.251,5.061],[-1.654,4.28],[1.029,3.13],[2.075,2.611]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[2.5,2.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"mm","mm":3,"nm":"Объединить контуры 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Com 2","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Com 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Com 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0}],"markers":[]} ================================================ FILE: Telegram/Resources/iv_html/highlight.9.12.0.css ================================================ .hljs{display:block;overflow-x:auto;padding:0.5em;background:#F0F0F0}.hljs,.hljs-subst{color:#444}.hljs-comment{color:#888888}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-selector-pseudo{color:#BC6060}.hljs-literal{color:#78A960}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold} ================================================ FILE: Telegram/Resources/iv_html/highlight.9.12.0.js ================================================ /*! highlight.js v9.12.0 | BSD3 License | git.io/hljslicense */ !function(e){var t="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):t&&(t.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return t.hljs}))}(function(e){function t(e){return e.replace(/&/g,"&").replace(//g,">")}function r(e){return e.nodeName.toLowerCase()}function a(e,t){var r=e&&e.exec(t);return r&&0===r.index}function n(e){return E.test(e)}function i(e){var t,r,a,i,s=e.className+" ";if(s+=e.parentNode?e.parentNode.className:"",r=M.exec(s))return w(r[1])?r[1]:"no-highlight";for(s=s.split(/\s+/),t=0,a=s.length;a>t;t++)if(i=s[t],n(i)||w(i))return i}function s(e){var t,r={},a=Array.prototype.slice.call(arguments,1);for(t in e)r[t]=e[t];return a.forEach(function(e){for(t in e)r[t]=e[t]}),r}function c(e){var t=[];return function a(e,n){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?n+=i.nodeValue.length:1===i.nodeType&&(t.push({event:"start",offset:n,node:i}),n=a(i,n),r(i).match(/br|hr|img|input/)||t.push({event:"stop",offset:n,node:i}));return n}(e,0),t}function o(e,a,n){function i(){return e.length&&a.length?e[0].offset!==a[0].offset?e[0].offset"}function c(e){u+=""}function o(e){("start"===e.event?s:c)(e.node)}for(var l=0,u="",d=[];e.length||a.length;){var b=i();if(u+=t(n.substring(l,b[0].offset)),l=b[0].offset,b===e){d.reverse().forEach(c);do o(b.splice(0,1)[0]),b=i();while(b===e&&b.length&&b[0].offset===l);d.reverse().forEach(s)}else"start"===b[0].event?d.push(b[0].node):d.pop(),o(b.splice(0,1)[0])}return u+t(n.substr(l))}function l(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(t){return s(e,{v:null},t)})),e.cached_variants||e.eW&&[s(e)]||[e]}function u(e){function t(e){return e&&e.source||e}function r(r,a){return new RegExp(t(r),"m"+(e.cI?"i":"")+(a?"g":""))}function a(n,i){if(!n.compiled){if(n.compiled=!0,n.k=n.k||n.bK,n.k){var s={},c=function(t,r){e.cI&&(r=r.toLowerCase()),r.split(" ").forEach(function(e){var r=e.split("|");s[r[0]]=[t,r[1]?Number(r[1]):1]})};"string"==typeof n.k?c("keyword",n.k):k(n.k).forEach(function(e){c(e,n.k[e])}),n.k=s}n.lR=r(n.l||/\w+/,!0),i&&(n.bK&&(n.b="\\b("+n.bK.split(" ").join("|")+")\\b"),n.b||(n.b=/\B|\b/),n.bR=r(n.b),n.e||n.eW||(n.e=/\B|\b/),n.e&&(n.eR=r(n.e)),n.tE=t(n.e)||"",n.eW&&i.tE&&(n.tE+=(n.e?"|":"")+i.tE)),n.i&&(n.iR=r(n.i)),null==n.r&&(n.r=1),n.c||(n.c=[]),n.c=Array.prototype.concat.apply([],n.c.map(function(e){return l("self"===e?n:e)})),n.c.forEach(function(e){a(e,n)}),n.starts&&a(n.starts,i);var o=n.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([n.tE,n.i]).map(t).filter(Boolean);n.t=o.length?r(o.join("|"),!0):{exec:function(){return null}}}}a(e)}function d(e,r,n,i){function s(e,t){var r,n;for(r=0,n=t.c.length;n>r;r++)if(a(t.c[r].bR,e))return t.c[r]}function c(e,t){if(a(e.eR,t)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?c(e.parent,t):void 0}function o(e,t){return!n&&a(t.iR,e)}function l(e,t){var r=v.cI?t[0].toLowerCase():t[0];return e.k.hasOwnProperty(r)&&e.k[r]}function p(e,t,r,a){var n=a?"":L.classPrefix,i='',i+t+s}function m(){var e,r,a,n;if(!N.k)return t(E);for(n="",r=0,N.lR.lastIndex=0,a=N.lR.exec(E);a;)n+=t(E.substring(r,a.index)),e=l(N,a),e?(M+=e[1],n+=p(e[0],t(a[0]))):n+=t(a[0]),r=N.lR.lastIndex,a=N.lR.exec(E);return n+t(E.substr(r))}function f(){var e="string"==typeof N.sL;if(e&&!x[N.sL])return t(E);var r=e?d(N.sL,E,!0,k[N.sL]):b(E,N.sL.length?N.sL:void 0);return N.r>0&&(M+=r.r),e&&(k[N.sL]=r.top),p(r.language,r.value,!1,!0)}function g(){C+=null!=N.sL?f():m(),E=""}function _(e){C+=e.cN?p(e.cN,"",!0):"",N=Object.create(e,{parent:{value:N}})}function h(e,t){if(E+=e,null==t)return g(),0;var r=s(t,N);if(r)return r.skip?E+=t:(r.eB&&(E+=t),g(),r.rB||r.eB||(E=t)),_(r,t),r.rB?0:t.length;var a=c(N,t);if(a){var n=N;n.skip?E+=t:(n.rE||n.eE||(E+=t),g(),n.eE&&(E=t));do N.cN&&(C+=R),N.skip||(M+=N.r),N=N.parent;while(N!==a.parent);return a.starts&&_(a.starts,""),n.rE?0:t.length}if(o(t,N))throw new Error('Illegal lexeme "'+t+'" for mode "'+(N.cN||"")+'"');return E+=t,t.length||1}var v=w(e);if(!v)throw new Error('Unknown language: "'+e+'"');u(v);var y,N=i||v,k={},C="";for(y=N;y!==v;y=y.parent)y.cN&&(C=p(y.cN,"",!0)+C);var E="",M=0;try{for(var B,S,$=0;;){if(N.t.lastIndex=$,B=N.t.exec(r),!B)break;S=h(r.substring($,B.index),B[0]),$=B.index+S}for(h(r.substr($)),y=N;y.parent;y=y.parent)y.cN&&(C+=R);return{r:M,value:C,language:e,top:N}}catch(A){if(A.message&&-1!==A.message.indexOf("Illegal"))return{r:0,value:t(r)};throw A}}function b(e,r){r=r||L.languages||k(x);var a={r:0,value:t(e)},n=a;return r.filter(w).forEach(function(t){var r=d(t,e,!1);r.language=t,r.r>n.r&&(n=r),r.r>a.r&&(n=a,a=r)}),n.language&&(a.second_best=n),a}function p(e){return L.tabReplace||L.useBR?e.replace(B,function(e,t){return L.useBR&&"\n"===e?"
":L.tabReplace?t.replace(/\t/g,L.tabReplace):""}):e}function m(e,t,r){var a=t?C[t]:r,n=[e.trim()];return e.match(/\bhljs\b/)||n.push("hljs"),-1===e.indexOf(a)&&n.push(a),n.join(" ").trim()}function f(e){var t,r,a,s,l,u=i(e);n(u)||(L.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):t=e,l=t.textContent,a=u?d(u,l,!0):b(l),r=c(t),r.length&&(s=document.createElementNS("http://www.w3.org/1999/xhtml","div"),s.innerHTML=a.value,a.value=o(r,c(s),l)),a.value=p(a.value),e.innerHTML=a.value,e.className=m(e.className,u,a.language),e.result={language:a.language,re:a.r},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.r}))}function g(e){L=s(L,e)}function _(){if(!_.called){_.called=!0;var e=document.querySelectorAll("pre code");N.forEach.call(e,f)}}function h(){addEventListener("DOMContentLoaded",_,!1),addEventListener("load",_,!1)}function v(t,r){var a=x[t]=r(e);a.aliases&&a.aliases.forEach(function(e){C[e]=t})}function y(){return k(x)}function w(e){return e=(e||"").toLowerCase(),x[e]||x[C[e]]}var N=[],k=Object.keys,x={},C={},E=/^(no-?highlight|plain|text)$/i,M=/\blang(?:uage)?-([\w-]+)\b/i,B=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,R="
",L={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=d,e.highlightAuto=b,e.fixMarkup=p,e.highlightBlock=f,e.configure=g,e.initHighlighting=_,e.initHighlightingOnLoad=h,e.registerLanguage=v,e.listLanguages=y,e.getLanguage=w,e.inherit=s,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(t,r,a){var n=e.inherit({cN:"comment",b:t,e:r,c:[]},a||{});return n.c.push(e.PWM),n.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),n},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e.registerLanguage("apache",function(e){var t={cN:"number",b:"[\\$%]\\d+"};return{aliases:["apacheconf"],cI:!0,c:[e.HCM,{cN:"section",b:""},{cN:"attribute",b:/\w+/,r:0,k:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{e:/$/,r:0,k:{literal:"on off all"},c:[{cN:"meta",b:"\\s\\[",e:"\\]$"},{cN:"variable",b:"[\\$%]\\{",e:"\\}",c:["self",t]},t,e.QSM]}}],i:/\S/}}),e.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},r={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,r,a,t]}}),e.registerLanguage("coffeescript",function(e){var t={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super yield import export from as default await then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",built_in:"npm require console print module global window document"},r="[A-Za-z$_][0-9A-Za-z$_]*",a={cN:"subst",b:/#\{/,e:/}/,k:t},n=[e.BNM,e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,a]},{b:/"/,e:/"/,c:[e.BE,a]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[a,e.HCM]},{b:"//[gim]*",r:0},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{b:"@"+r},{sL:"javascript",eB:!0,eE:!0,v:[{b:"```",e:"```"},{b:"`",e:"`"}]}];a.c=n;var i=e.inherit(e.TM,{b:r}),s="(\\(.*\\))?\\s*\\B[-=]>",c={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(n)}]};return{aliases:["coffee","cson","iced"],k:t,i:/\/\*/,c:n.concat([e.C("###","###"),e.HCM,{cN:"function",b:"^\\s*"+r+"\\s*=\\s*"+s,e:"[-=]>",rB:!0,c:[i,c]},{b:/[:\(,=]\s*/,r:0,c:[{cN:"function",b:s,e:"[-=]>",rB:!0,c:[c]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[i]},i]},{b:r+":",e:":",rB:!0,rE:!0,r:0}])}}),e.registerLanguage("cpp",function(e){var t={cN:"keyword",b:"\\b[a-z\\d_]*_t\\b"},r={cN:"string",v:[{b:'(u8?|U)?L?"',e:'"',i:"\\n",c:[e.BE]},{b:'(u8?|U)?R"',e:'"',c:[e.BE]},{b:"'\\\\?.",e:"'",i:"."}]},a={cN:"number",v:[{b:"\\b(0b[01']+)"},{b:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{b:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],r:0},n={cN:"meta",b:/#\s*[a-z]+\b/,e:/$/,k:{"meta-keyword":"if else elif endif define undef warning error line pragma ifdef ifndef include"},c:[{b:/\\\n/,r:0},e.inherit(r,{cN:"meta-string"}),{cN:"meta-string",b:/<[^\n>]*>/,e:/$/,i:"\\n"},e.CLCM,e.CBCM]},i=e.IR+"\\s*\\(",s={keyword:"int float while private char catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignof constexpr decltype noexcept static_assert thread_local restrict _Bool complex _Complex _Imaginary atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and or not",built_in:"std string cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr",literal:"true false nullptr NULL"},c=[t,e.CLCM,e.CBCM,a,r];return{aliases:["c","cc","h","c++","h++","hpp"],k:s,i:"",k:s,c:["self",t]},{b:e.IR+"::",k:s},{v:[{b:/=/,e:/;/},{b:/\(/,e:/\)/},{bK:"new throw return else",e:/;/}],k:s,c:c.concat([{b:/\(/,e:/\)/,k:s,c:c.concat(["self"]),r:0}]),r:0},{cN:"function",b:"("+e.IR+"[\\*&\\s]+)+"+i,rB:!0,e:/[{;=]/,eE:!0,k:s,i:/[^\w\s\*&]/,c:[{b:i,rB:!0,c:[e.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:s,r:0,c:[e.CLCM,e.CBCM,r,a,t]},e.CLCM,e.CBCM,n]},{cN:"class",bK:"class struct",e:/[{;:]/,c:[{b://,c:["self"]},e.TM]}]),exports:{preprocessor:n,strings:r,k:s}}}),e.registerLanguage("cs",function(e){var t={keyword:"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long nameof object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let on orderby partial remove select set value var where yield",literal:"null false true"},r={cN:"string",b:'@"',e:'"',c:[{b:'""'}]},a=e.inherit(r,{i:/\n/}),n={cN:"subst",b:"{",e:"}",k:t},i=e.inherit(n,{i:/\n/}),s={cN:"string",b:/\$"/,e:'"',i:/\n/,c:[{b:"{{"},{b:"}}"},e.BE,i]},c={cN:"string",b:/\$@"/,e:'"',c:[{b:"{{"},{b:"}}"},{b:'""'},n]},o=e.inherit(c,{i:/\n/,c:[{b:"{{"},{b:"}}"},{b:'""'},i]});n.c=[c,s,r,e.ASM,e.QSM,e.CNM,e.CBCM],i.c=[o,s,a,e.ASM,e.QSM,e.CNM,e.inherit(e.CBCM,{i:/\n/})];var l={v:[c,s,r,e.ASM,e.QSM]},u=e.IR+"(<"+e.IR+"(\\s*,\\s*"+e.IR+")*>)?(\\[\\])?";return{aliases:["csharp"],k:t,i:/::/,c:[e.C("///","$",{rB:!0,c:[{cN:"doctag",v:[{b:"///",r:0},{b:""},{b:""}]}]}),e.CLCM,e.CBCM,{cN:"meta",b:"#",e:"$",k:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},l,e.CNM,{bK:"class interface",e:/[{;=]/,i:/[^\s:]/,c:[e.TM,e.CLCM,e.CBCM]},{bK:"namespace",e:/[{;=]/,i:/[^\s:]/,c:[e.inherit(e.TM,{b:"[a-zA-Z](\\.?\\w)*"}),e.CLCM,e.CBCM]},{cN:"meta",b:"^\\s*\\[",eB:!0,e:"\\]",eE:!0,c:[{cN:"meta-string",b:/"/,e:/"/}]},{bK:"new return throw await else",r:0},{cN:"function",b:"("+u+"\\s+)+"+e.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.IR+"\\s*\\(",rB:!0,c:[e.TM],r:0},{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,r:0,c:[l,e.CNM,e.CBCM]},e.CLCM,e.CBCM]}]}}),e.registerLanguage("css",function(e){var t="[a-zA-Z-][a-zA-Z0-9_-]*",r={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:t,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,r]}]}}),e.registerLanguage("diff",function(e){return{aliases:["patch"],c:[{cN:"meta",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"comment",v:[{b:/Index: /,e:/$/},{b:/={3,}/,e:/$/},{b:/^\-{3}/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+{3}/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"addition",b:"^\\!",e:"$"}]}}),e.registerLanguage("http",function(e){var t="HTTP/[0-9\\.]+";return{aliases:["https"],i:"\\S",c:[{b:"^"+t,e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{b:"^[A-Z]+ (.*?) "+t+"$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0},{b:t},{cN:"keyword",b:"[A-Z]+"}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{e:"$",r:0}},{b:"\\n\\n",starts:{sL:[],eW:!0}}]}}),e.registerLanguage("ini",function(e){var t={cN:"string",c:[e.BE],v:[{b:"'''",e:"'''",r:10},{b:'"""',e:'"""',r:10},{b:'"',e:'"'},{b:"'",e:"'"}]};return{aliases:["toml"],cI:!0,i:/\S/,c:[e.C(";","$"),e.HCM,{cN:"section",b:/^\s*\[+/,e:/\]+/},{b:/^[a-z0-9\[\]_-]+\s*=\s*/,e:"$",rB:!0,c:[{cN:"attr",b:/[a-z0-9\[\]_-]+/},{b:/=/,eW:!0,r:0,c:[{cN:"literal",b:/\bon|off|true|false|yes|no\b/},{cN:"variable",v:[{b:/\$[\w\d"][\w\d_]*/},{b:/\$\{(.*?)}/}]},t,{cN:"number",b:/([\+\-]+)?[\d]+_[\d_]+/},e.NM]}]}]}}),e.registerLanguage("java",function(e){var t="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",r=t+"(<"+t+"(\\s*,\\s*"+t+")*>)?",a="false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",n="\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",i={cN:"number",b:n,r:0};return{aliases:["jsp"],k:a,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return else",r:0},{cN:"function",b:"("+r+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:a,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:a,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},i,{cN:"meta",b:"@[A-Za-z]+"}]}}),e.registerLanguage("javascript",function(e){var t="[A-Za-z$_][0-9A-Za-z$_]*",r={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:r,c:[]},i={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,i,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:r,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,i,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:t+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:t,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+t+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:t},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:r,c:s}]}]},{b://,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:t}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}}),e.registerLanguage("json",function(e){var t={literal:"true false null"},r=[e.QSM,e.CNM],a={e:",",eW:!0,eE:!0,c:r,k:t},n={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(a,{b:/:/})],i:"\\S"},i={b:"\\[",e:"\\]",c:[e.inherit(a)],i:"\\S"};return r.splice(r.length,0,n,i),{c:r,k:t,i:"\\S"}}),e.registerLanguage("makefile",function(e){var t={cN:"variable",v:[{b:"\\$\\("+e.UIR+"\\)",c:[e.BE]},{b:/\$[@%`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},e.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0}]},{cN:"tag",b:"|$)",e:">",k:{name:"style"},c:[r],starts:{e:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[r],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},r]}]}}),e.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"section",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"quote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"^```w*s*$",e:"^```s*$"},{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"string",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"symbol",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:/^\[[^\n]+\]:/,rB:!0,c:[{cN:"symbol",b:/\[/,e:/\]/,eB:!0,eE:!0},{cN:"link",b:/:\s*/,e:/$/,eB:!0}]}]}}),e.registerLanguage("nginx",function(e){var t={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+e.UIR}]},r={eW:!0,l:"[a-z/_]+",k:{literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[e.HCM,{cN:"string",c:[e.BE,t],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{b:"([a-z]+):/",e:"\\s",eW:!0,eE:!0,c:[t]},{cN:"regexp",c:[e.BE,t],v:[{b:"\\s\\^",e:"\\s|{|;",rE:!0},{b:"~\\*?\\s+",e:"\\s|{|;",rE:!0},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},t]};return{aliases:["nginxconf"],c:[e.HCM,{b:e.UIR+"\\s+{",rB:!0,e:"{",c:[{cN:"section",b:e.UIR}],r:0},{b:e.UIR+"\\s",e:";|{",rB:!0,c:[{cN:"attribute",b:e.UIR,starts:r}],r:0}],i:"[^\\s\\}]"}}),e.registerLanguage("objectivec",function(e){var t={cN:"built_in",b:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"},r={keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},a=/[a-zA-Z@][a-zA-Z0-9_]*/,n="@interface @class @protocol @implementation";return{aliases:["mm","objc","obj-c"],k:r,l:a,i:""}]}]},{cN:"class",b:"("+n.split(" ").join("|")+")\\b",e:"({|$)",eE:!0,k:n,l:a,c:[e.UTM]},{b:"\\."+e.UIR,r:0}]}}),e.registerLanguage("perl",function(e){var t="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when",r={cN:"subst",b:"[$@]\\{",e:"\\}",k:t},a={b:"->{",e:"}"},n={v:[{b:/\$\d/},{b:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{b:/[\$%@][^\s\w{]/,r:0}]},i=[e.BE,r,n],s=[n,e.HCM,e.C("^\\=\\w","\\=cut",{eW:!0}),a,{cN:"string",c:i,v:[{b:"q[qwxr]?\\s*\\(",e:"\\)",r:5},{b:"q[qwxr]?\\s*\\[",e:"\\]",r:5},{b:"q[qwxr]?\\s*\\{",e:"\\}",r:5},{b:"q[qwxr]?\\s*\\|",e:"\\|",r:5},{b:"q[qwxr]?\\s*\\<",e:"\\>",r:5},{b:"qw\\s+q",e:"q",r:5},{b:"'",e:"'",c:[e.BE]},{b:'"',e:'"'},{b:"`",e:"`",c:[e.BE]},{b:"{\\w+}",c:[],r:0},{b:"-?\\w+\\s*\\=\\>",c:[],r:0}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\/\\/|"+e.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[e.HCM,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[e.BE],r:0}]},{cN:"function",bK:"sub",e:"(\\s*\\(.*?\\))?[;{]",eE:!0,r:5,c:[e.TM]},{b:"-\\w\\b",r:0},{b:"^__DATA__$",e:"^__END__$",sL:"mojolicious",c:[{b:"^@@.*",e:"$",cN:"comment"}]}];return r.c=s,a.c=s,{aliases:["pl","pm"],l:/[\w\.]+/,k:t,c:s}}),e.registerLanguage("php",function(e){var t={b:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},r={cN:"meta",b:/<\?(php)?|\?>/},a={cN:"string",c:[e.BE,r],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},n={v:[e.BNM,e.CNM]};return{aliases:["php3","php4","php5","php6"],cI:!0,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[e.HCM,e.C("//","$",{c:[r]}),e.C("/\\*","\\*/",{c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.C("__halt_compiler.+?;",!1,{eW:!0,k:"__halt_compiler",l:e.UIR}),{cN:"string",b:/<<<['"]?\w+['"]?$/,e:/^\w+;?$/,c:[e.BE,{cN:"subst",v:[{b:/\$\w+/},{b:/\{\$/,e:/\}/}]}]},r,{cN:"keyword",b:/\$this\b/},t,{b:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{cN:"function",bK:"function",e:/[;{]/,eE:!0,i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",t,e.CBCM,a,n]}]},{cN:"class",bK:"class interface",e:"{",eE:!0,i:/[:\(\$"]/,c:[{bK:"extends implements"},e.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[e.UTM]},{bK:"use",e:";",c:[e.UTM]},{b:"=>"},a,n]}}),e.registerLanguage("python",function(e){var t={keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda async await nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},r={cN:"meta",b:/^(>>>|\.\.\.) /},a={cN:"subst",b:/\{/,e:/\}/,k:t,i:/#/},n={cN:"string",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[r],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[r],r:10},{b:/(fr|rf|f)'''/,e:/'''/,c:[r,a]},{b:/(fr|rf|f)"""/,e:/"""/,c:[r,a]},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)"/,e:/"/},{b:/(fr|rf|f)'/,e:/'/,c:[a]},{b:/(fr|rf|f)"/,e:/"/,c:[a]},e.ASM,e.QSM]},i={cN:"number",r:0,v:[{b:e.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:e.CNR+"[lLjJ]?"}]},s={cN:"params",b:/\(/,e:/\)/,c:["self",r,i,n]};return a.c=[n,i,r],{aliases:["py","gyp"],k:t,i:/(<\/|->|\?)|=>/,c:[r,i,n,e.HCM,{v:[{cN:"function",bK:"def"},{cN:"class",bK:"class"}],e:/:/,i:/[${=;\n,]/,c:[e.UTM,s,{b:/->/,eW:!0,k:"None"}]},{cN:"meta",b:/^[\t ]*@/,e:/$/},{b:/\b(print|exec)\(/}]}}),e.registerLanguage("ruby",function(e){ var t="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",r={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},a={cN:"doctag",b:"@[A-Za-z]+"},n={b:"#<",e:">"},i=[e.C("#","$",{c:[a]}),e.C("^\\=begin","^\\=end",{c:[a],r:10}),e.C("^__END__","\\n$")],s={cN:"subst",b:"#\\{",e:"}",k:r},c={cN:"string",c:[e.BE,s],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{b:/<<(-?)\w+$/,e:/^\s*\w+$/}]},o={cN:"params",b:"\\(",e:"\\)",endsParent:!0,k:r},l=[c,n,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{b:"<\\s*",c:[{b:"("+e.IR+"::)?"+e.IR}]}].concat(i)},{cN:"function",bK:"def",e:"$|;",c:[e.inherit(e.TM,{b:t}),o].concat(i)},{b:e.IR+"::"},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":(?!\\s)",c:[c,{b:t}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{cN:"params",b:/\|/,e:/\|/,k:r},{b:"("+e.RSR+"|unless)\\s*",k:"unless",c:[n,{cN:"regexp",c:[e.BE,s],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}].concat(i),r:0}].concat(i);s.c=l,o.c=l;var u="[>?]>",d="[\\w#]+\\(\\w+\\):\\d+:\\d+>",b="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",p=[{b:/^\s*=>/,starts:{e:"$",c:l}},{cN:"meta",b:"^("+u+"|"+d+"|"+b+")",starts:{e:"$",c:l}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:r,i:/\/\*/,c:i.concat(p).concat(l)}}),e.registerLanguage("shell",function(e){return{aliases:["console"],c:[{cN:"meta",b:"^\\s{0,3}[\\w\\d\\[\\]()@-]*[>%$#]",starts:{e:"$",sL:"bash"}}]}}),e.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>{}*#]/,c:[{bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment",e:/;/,eW:!0,l:/[\w\.]+/,k:{keyword:"abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text varchar varying void"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}}),e}); ================================================ FILE: Telegram/Resources/iv_html/morphdom-umd.min.2.7.2.js ================================================ (function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=global||self,global.morphdom=factory())})(this,function(){"use strict";var DOCUMENT_FRAGMENT_NODE=11;function morphAttrs(fromNode,toNode){var toNodeAttrs=toNode.attributes;var attr;var attrName;var attrNamespaceURI;var attrValue;var fromValue;if(toNode.nodeType===DOCUMENT_FRAGMENT_NODE||fromNode.nodeType===DOCUMENT_FRAGMENT_NODE){return}for(var i=toNodeAttrs.length-1;i>=0;i--){attr=toNodeAttrs[i];attrName=attr.name;attrNamespaceURI=attr.namespaceURI;attrValue=attr.value;if(attrNamespaceURI){attrName=attr.localName||attrName;fromValue=fromNode.getAttributeNS(attrNamespaceURI,attrName);if(fromValue!==attrValue){if(attr.prefix==="xmlns"){attrName=attr.name}fromNode.setAttributeNS(attrNamespaceURI,attrName,attrValue)}}else{fromValue=fromNode.getAttribute(attrName);if(fromValue!==attrValue){fromNode.setAttribute(attrName,attrValue)}}}var fromNodeAttrs=fromNode.attributes;for(var d=fromNodeAttrs.length-1;d>=0;d--){attr=fromNodeAttrs[d];attrName=attr.name;attrNamespaceURI=attr.namespaceURI;if(attrNamespaceURI){attrName=attr.localName||attrName;if(!toNode.hasAttributeNS(attrNamespaceURI,attrName)){fromNode.removeAttributeNS(attrNamespaceURI,attrName)}}else{if(!toNode.hasAttribute(attrName)){fromNode.removeAttribute(attrName)}}}}var range;var NS_XHTML="http://www.w3.org/1999/xhtml";var doc=typeof document==="undefined"?undefined:document;var HAS_TEMPLATE_SUPPORT=!!doc&&"content"in doc.createElement("template");var HAS_RANGE_SUPPORT=!!doc&&doc.createRange&&"createContextualFragment"in doc.createRange();function createFragmentFromTemplate(str){var template=doc.createElement("template");template.innerHTML=str;return template.content.childNodes[0]}function createFragmentFromRange(str){if(!range){range=doc.createRange();range.selectNode(doc.body)}var fragment=range.createContextualFragment(str);return fragment.childNodes[0]}function createFragmentFromWrap(str){var fragment=doc.createElement("body");fragment.innerHTML=str;return fragment.childNodes[0]}function toElement(str){str=str.trim();if(HAS_TEMPLATE_SUPPORT){return createFragmentFromTemplate(str)}else if(HAS_RANGE_SUPPORT){return createFragmentFromRange(str)}return createFragmentFromWrap(str)}function compareNodeNames(fromEl,toEl){var fromNodeName=fromEl.nodeName;var toNodeName=toEl.nodeName;var fromCodeStart,toCodeStart;if(fromNodeName===toNodeName){return true}fromCodeStart=fromNodeName.charCodeAt(0);toCodeStart=toNodeName.charCodeAt(0);if(fromCodeStart<=90&&toCodeStart>=97){return fromNodeName===toNodeName.toUpperCase()}else if(toCodeStart<=90&&fromCodeStart>=97){return toNodeName===fromNodeName.toUpperCase()}else{return false}}function createElementNS(name,namespaceURI){return!namespaceURI||namespaceURI===NS_XHTML?doc.createElement(name):doc.createElementNS(namespaceURI,name)}function moveChildren(fromEl,toEl){var curChild=fromEl.firstChild;while(curChild){var nextChild=curChild.nextSibling;toEl.appendChild(curChild);curChild=nextChild}return toEl}function syncBooleanAttrProp(fromEl,toEl,name){if(fromEl[name]!==toEl[name]){fromEl[name]=toEl[name];if(fromEl[name]){fromEl.setAttribute(name,"")}else{fromEl.removeAttribute(name)}}}var specialElHandlers={OPTION:function(fromEl,toEl){var parentNode=fromEl.parentNode;if(parentNode){var parentName=parentNode.nodeName.toUpperCase();if(parentName==="OPTGROUP"){parentNode=parentNode.parentNode;parentName=parentNode&&parentNode.nodeName.toUpperCase()}if(parentName==="SELECT"&&!parentNode.hasAttribute("multiple")){if(fromEl.hasAttribute("selected")&&!toEl.selected){fromEl.setAttribute("selected","selected");fromEl.removeAttribute("selected")}parentNode.selectedIndex=-1}}syncBooleanAttrProp(fromEl,toEl,"selected")},INPUT:function(fromEl,toEl){syncBooleanAttrProp(fromEl,toEl,"checked");syncBooleanAttrProp(fromEl,toEl,"disabled");if(fromEl.value!==toEl.value){fromEl.value=toEl.value}if(!toEl.hasAttribute("value")){fromEl.removeAttribute("value")}},TEXTAREA:function(fromEl,toEl){var newValue=toEl.value;if(fromEl.value!==newValue){fromEl.value=newValue}var firstChild=fromEl.firstChild;if(firstChild){var oldValue=firstChild.nodeValue;if(oldValue==newValue||!newValue&&oldValue==fromEl.placeholder){return}firstChild.nodeValue=newValue}},SELECT:function(fromEl,toEl){if(!toEl.hasAttribute("multiple")){var selectedIndex=-1;var i=0;var curChild=fromEl.firstChild;var optgroup;var nodeName;while(curChild){nodeName=curChild.nodeName&&curChild.nodeName.toUpperCase();if(nodeName==="OPTGROUP"){optgroup=curChild;curChild=optgroup.firstChild}else{if(nodeName==="OPTION"){if(curChild.hasAttribute("selected")){selectedIndex=i;break}i++}curChild=curChild.nextSibling;if(!curChild&&optgroup){curChild=optgroup.nextSibling;optgroup=null}}}fromEl.selectedIndex=selectedIndex}}};var ELEMENT_NODE=1;var DOCUMENT_FRAGMENT_NODE$1=11;var TEXT_NODE=3;var COMMENT_NODE=8;function noop(){}function defaultGetNodeKey(node){if(node){return node.getAttribute&&node.getAttribute("id")||node.id}}function morphdomFactory(morphAttrs){return function morphdom(fromNode,toNode,options){if(!options){options={}}if(typeof toNode==="string"){if(fromNode.nodeName==="#document"||fromNode.nodeName==="HTML"||fromNode.nodeName==="BODY"){var toNodeHtml=toNode;toNode=doc.createElement("html");toNode.innerHTML=toNodeHtml}else{toNode=toElement(toNode)}}else if(toNode.nodeType===DOCUMENT_FRAGMENT_NODE$1){toNode=toNode.firstElementChild}var getNodeKey=options.getNodeKey||defaultGetNodeKey;var onBeforeNodeAdded=options.onBeforeNodeAdded||noop;var onNodeAdded=options.onNodeAdded||noop;var onBeforeElUpdated=options.onBeforeElUpdated||noop;var onElUpdated=options.onElUpdated||noop;var onBeforeNodeDiscarded=options.onBeforeNodeDiscarded||noop;var onNodeDiscarded=options.onNodeDiscarded||noop;var onBeforeElChildrenUpdated=options.onBeforeElChildrenUpdated||noop;var skipFromChildren=options.skipFromChildren||noop;var addChild=options.addChild||function(parent,child){return parent.appendChild(child)};var childrenOnly=options.childrenOnly===true;var fromNodesLookup=Object.create(null);var keyedRemovalList=[];function addKeyedRemoval(key){keyedRemovalList.push(key)}function walkDiscardedChildNodes(node,skipKeyedNodes){if(node.nodeType===ELEMENT_NODE){var curChild=node.firstChild;while(curChild){var key=undefined;if(skipKeyedNodes&&(key=getNodeKey(curChild))){addKeyedRemoval(key)}else{onNodeDiscarded(curChild);if(curChild.firstChild){walkDiscardedChildNodes(curChild,skipKeyedNodes)}}curChild=curChild.nextSibling}}}function removeNode(node,parentNode,skipKeyedNodes){if(onBeforeNodeDiscarded(node)===false){return}if(parentNode){parentNode.removeChild(node)}onNodeDiscarded(node);walkDiscardedChildNodes(node,skipKeyedNodes)}function indexTree(node){if(node.nodeType===ELEMENT_NODE||node.nodeType===DOCUMENT_FRAGMENT_NODE$1){var curChild=node.firstChild;while(curChild){var key=getNodeKey(curChild);if(key){fromNodesLookup[key]=curChild}indexTree(curChild);curChild=curChild.nextSibling}}}indexTree(fromNode);function handleNodeAdded(el){onNodeAdded(el);var curChild=el.firstChild;while(curChild){var nextSibling=curChild.nextSibling;var key=getNodeKey(curChild);if(key){var unmatchedFromEl=fromNodesLookup[key];if(unmatchedFromEl&&compareNodeNames(curChild,unmatchedFromEl)){curChild.parentNode.replaceChild(unmatchedFromEl,curChild);morphEl(unmatchedFromEl,curChild)}else{handleNodeAdded(curChild)}}else{handleNodeAdded(curChild)}curChild=nextSibling}}function cleanupFromEl(fromEl,curFromNodeChild,curFromNodeKey){while(curFromNodeChild){var fromNextSibling=curFromNodeChild.nextSibling;if(curFromNodeKey=getNodeKey(curFromNodeChild)){addKeyedRemoval(curFromNodeKey)}else{removeNode(curFromNodeChild,fromEl,true)}curFromNodeChild=fromNextSibling}}function morphEl(fromEl,toEl,childrenOnly){var toElKey=getNodeKey(toEl);if(toElKey){delete fromNodesLookup[toElKey]}if(!childrenOnly){if(onBeforeElUpdated(fromEl,toEl)===false){return}morphAttrs(fromEl,toEl);onElUpdated(fromEl);if(onBeforeElChildrenUpdated(fromEl,toEl)===false){return}}if(fromEl.nodeName!=="TEXTAREA"){morphChildren(fromEl,toEl)}else{specialElHandlers.TEXTAREA(fromEl,toEl)}}function morphChildren(fromEl,toEl){var skipFrom=skipFromChildren(fromEl,toEl);var curToNodeChild=toEl.firstChild;var curFromNodeChild=fromEl.firstChild;var curToNodeKey;var curFromNodeKey;var fromNextSibling;var toNextSibling;var matchingFromEl;outer:while(curToNodeChild){toNextSibling=curToNodeChild.nextSibling;curToNodeKey=getNodeKey(curToNodeChild);while(!skipFrom&&curFromNodeChild){fromNextSibling=curFromNodeChild.nextSibling;if(curToNodeChild.isSameNode&&curToNodeChild.isSameNode(curFromNodeChild)){curToNodeChild=toNextSibling;curFromNodeChild=fromNextSibling;continue outer}curFromNodeKey=getNodeKey(curFromNodeChild);var curFromNodeType=curFromNodeChild.nodeType;var isCompatible=undefined;if(curFromNodeType===curToNodeChild.nodeType){if(curFromNodeType===ELEMENT_NODE){if(curToNodeKey){if(curToNodeKey!==curFromNodeKey){if(matchingFromEl=fromNodesLookup[curToNodeKey]){if(fromNextSibling===matchingFromEl){isCompatible=false}else{fromEl.insertBefore(matchingFromEl,curFromNodeChild);if(curFromNodeKey){addKeyedRemoval(curFromNodeKey)}else{removeNode(curFromNodeChild,fromEl,true)}curFromNodeChild=matchingFromEl;curFromNodeKey=getNodeKey(curFromNodeChild)}}else{isCompatible=false}}}else if(curFromNodeKey){isCompatible=false}isCompatible=isCompatible!==false&&compareNodeNames(curFromNodeChild,curToNodeChild);if(isCompatible){morphEl(curFromNodeChild,curToNodeChild)}}else if(curFromNodeType===TEXT_NODE||curFromNodeType==COMMENT_NODE){isCompatible=true;if(curFromNodeChild.nodeValue!==curToNodeChild.nodeValue){curFromNodeChild.nodeValue=curToNodeChild.nodeValue}}}if(isCompatible){curToNodeChild=toNextSibling;curFromNodeChild=fromNextSibling;continue outer}if(curFromNodeKey){addKeyedRemoval(curFromNodeKey)}else{removeNode(curFromNodeChild,fromEl,true)}curFromNodeChild=fromNextSibling}if(curToNodeKey&&(matchingFromEl=fromNodesLookup[curToNodeKey])&&compareNodeNames(matchingFromEl,curToNodeChild)){if(!skipFrom){addChild(fromEl,matchingFromEl)}morphEl(matchingFromEl,curToNodeChild)}else{var onBeforeNodeAddedResult=onBeforeNodeAdded(curToNodeChild);if(onBeforeNodeAddedResult!==false){if(onBeforeNodeAddedResult){curToNodeChild=onBeforeNodeAddedResult}if(curToNodeChild.actualize){curToNodeChild=curToNodeChild.actualize(fromEl.ownerDocument||doc)}addChild(fromEl,curToNodeChild);handleNodeAdded(curToNodeChild)}}curToNodeChild=toNextSibling;curFromNodeChild=fromNextSibling}cleanupFromEl(fromEl,curFromNodeChild,curFromNodeKey);var specialElHandler=specialElHandlers[fromEl.nodeName];if(specialElHandler){specialElHandler(fromEl,toEl)}}var morphedNode=fromNode;var morphedNodeType=morphedNode.nodeType;var toNodeType=toNode.nodeType;if(!childrenOnly){if(morphedNodeType===ELEMENT_NODE){if(toNodeType===ELEMENT_NODE){if(!compareNodeNames(fromNode,toNode)){onNodeDiscarded(fromNode);morphedNode=moveChildren(fromNode,createElementNS(toNode.nodeName,toNode.namespaceURI))}}else{morphedNode=toNode}}else if(morphedNodeType===TEXT_NODE||morphedNodeType===COMMENT_NODE){if(toNodeType===morphedNodeType){if(morphedNode.nodeValue!==toNode.nodeValue){morphedNode.nodeValue=toNode.nodeValue}return morphedNode}else{morphedNode=toNode}}}if(morphedNode===toNode){onNodeDiscarded(fromNode)}else{if(toNode.isSameNode&&toNode.isSameNode(morphedNode)){return}morphEl(morphedNode,toNode,childrenOnly);if(keyedRemovalList){for(var i=0,len=keyedRemovalList.length;i li, article ol > li { padding-left: 4px; } article.rtl ul > li, article.rtl ol > li { padding-right: 4px; padding-left: 0; } /*article ul > li { position: relative; } article ul > li:before { content: '\2022'; position: absolute; display: block; font-size: 163%; left: -19px; top: 1px; } article.rtl ul > li:before { left: auto; right: -19px; }*/ article ul ul, article ul ol, article ol ul, article ol ol { margin: 0 0 12px; } article table { width: 100%; border-collapse: collapse; } article table.bordered, article table.bordered td, article table.bordered th { border: 1px solid var(--td-history-to-down-shadow); } article table.striped tr:nth-child(odd) td { background-color: var(--td-box-divider-bg); } article table caption { font-size: 15px; line-height: 18px; margin: 4px 0 7px; text-align: left; color: var(--td-window-sub-text-fg); } article.rtl table caption { text-align: right; } article td, article th { font-size: 15px; line-height: 21px; padding: 6px 5px 5px; background-color: var(--td-window-bg); vertical-align: middle; font-weight: normal; text-align: left; } article th { background-color: var(--td-box-divider-bg); } article.rtl table td, article.rtl table th { text-align: right; } article details { position: relative; margin: 0 0 12px; padding: 0 0 1px; } article details:before { content: ''; display: block; border-bottom: 1px solid var(--td-history-to-down-shadow); position: absolute; left: 18px; right: 0; bottom: 0; } article.rtl details:before { right: 18px; left: 0; } article details + details { margin-top: -12px; } article details > details:last-child { margin-bottom: -1px; } article summary { padding: 10px 18px 10px 42px; line-height: 25px; min-height: 25px; } article.rtl summary { padding-left: 18px; padding-right: 42px; } article summary:hover { cursor: pointer; } article summary:focus { outline: none; } article summary::-webkit-details-marker { display: none; } article summary::marker { content: ''; } article summary:before { content: ''; background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAICAYAAADN5B7xAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAH1JREFUeNqEjUEKgCAQRSfrNi1bdZFadJjsMC46SSAIHqjB5mcFqdFfhD3eUyKZtb6ln92O2janmXdvrRu+ZTfAgasu1jAHU4qiHAwc/Ff4oCQKsxxZ0NT33XrxUTjkWvgiXFf3TWkU6Vt+XihH515yFiQRpfLnEMUw3yHAABZNTT9emBrvAAAAAElFTkSuQmCC'); transition: all .2s ease; display: inline-block; position: absolute; width: 12px; height: 8px; left: 18px; top: 18px; } article.rtl summary:before { right: 18px; left: auto; } @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { article summary:before { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAQCAYAAAAMJL+VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPxJREFUeNq8lEESgiAUhgFbZ0epSW28gB2pZbrrSukBHDWto1TrwHih45AiaDOxesLP9w1PBlzXNfrLSNPqkGWV8ysHGMBqv4mAlyFC7MRPk+T51Z0Lh73AAJZgIoRFUR/bEMb4TggJPG9TTIUzxmIuWHWzOCLfQQgwRiedRMBpIsObFvn+NgSTLEE2bCiKm6eDQ0bAkS2v4AjYuPvJcqtEu9DDshaB665zFZzSV6yCfyr5JplLTOA9wZiEg/a+72Qic9nxubMOPijQSZraCK4UjEiezSVYmsBHBSrJAEIJ1wr0knG4kUAt0cONBX2JGXzGi1uG7SNmOt4CDADc4r+K4txg+wAAAABJRU5ErkJggg=='); background-size: 12px 8px; } } article details[open] > summary:before { /*transform: rotateZ(-180deg);*/ transform: scaleY(-1); } article li summary { padding-left: 24px; } article li details:before, article li summary:before { left: 0; } img, video, iframe { max-width: 100%; max-height: 480px; vertical-align: top; } video { width: 100%; } audio { width: 100%; width: calc(100% - 36px); margin: 0 18px; vertical-align: top; } img { font-size: 12px; line-height: 14px; color: var(--td-window-sub-text-fg); } img.pic { max-height: none; font-size: inherit; vertical-align: middle; position: relative; top: -0.1em; } img.pic.optional { opacity: 0.4; } body:hover img.pic.optional { opacity: 1; } iframe.autosize { max-height: none; } .iframe-wrap { max-width: 100%; vertical-align: top; display: inline-block; position: relative; } .iframe-wrap iframe { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } figure { margin: 0 0 16px; padding: 0; text-align: center; position: relative; } figure.nowide { margin-left: 18px; margin-right: 18px; } figure.nowide figcaption { padding-left: 0; padding-right: 0; } ul figure.nowide, ol figure.nowide { margin: 0 0 12px; } figure > figure { margin: 0; } figcaption { font-size: 15px; color: var(--td-window-sub-text-fg); padding: 6px 18px 0; line-height: 19px; text-align: left; } article.rtl figcaption { text-align: right; } ul figcaption, ol figcaption { padding-left: 0; padding-right: 0; } figcaption > cite { font-family: var(--font-sans); font-size: 12px; display: block; line-height: 15px; padding: 2px 0 0; font-style: normal; } footer { margin: 12px 18px; color: var(--td-window-sub-text-fg); } figure.slideshow-wrap { position: relative; } figure.slideshow { position: absolute; top: 0px; white-space: nowrap; width: 100%; background: #000; overflow: hidden; } figure.slideshow a { transition: margin 200ms ease-in-out; } figure.slideshow .photo-wrap, figure.slideshow .video-wrap { position: static !important; display: inline-block; margin: 0; vertical-align: middle; } .slideshow-buttons { position: absolute; width: 100%; bottom: 10px; white-space: nowrap; overflow: hidden; z-index: 5; } .slideshow-buttons > fieldset { padding: 0; margin: 0; border: none; line-height: 0; overflow: hidden; overflow-x: auto; min-width: auto; } .slideshow-buttons label { display: inline-block; padding: 7px; cursor: pointer; } .slideshow-buttons input { position: absolute; left: -10000px; } .slideshow-buttons label i { display: inline-block; background: #fff; box-shadow: 0 0 3px rgba(0, 0, 0, .4); border-radius: 3.5px; width: 7px; height: 7px; opacity: .6; transition: opacity .3s; } .slideshow-buttons input:checked ~ i { opacity: 1; } .slideshow-next, .slideshow-prev { position: absolute; z-index: 4; top: 0; width: 25%; max-width: 128px; height: 100%; cursor: pointer; transition: opacity 200ms ease-in-out; user-select: none; opacity: 0.6; } .slideshow-next { right: 0; background: linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,0.6) 100%); } .slideshow-prev { left: 0; background: linear-gradient(to left, rgba(0,0,0,0) 0%, rgba(0,0,0,0.6) 100%); } .slideshow-next:hover { opacity: 1; } .slideshow-prev:hover { opacity: 1; } .slideshow-prev svg, .slideshow-next svg { fill: none; top: calc(50% - 12px); position: absolute; z-index: 5; width: 24px; height: 24px; pointer-events: none; } .slideshow-prev svg { left: calc(min(50% - 12px, 20px)); } .slideshow-next svg { right: calc(min(50% - 12px, 20px)); } .slideshow-prev path, .slideshow-next path { stroke-width: 1.4; stroke: #fff; } figure.collage-wrap { margin: 0px 12px; } figure.collage-wrap figcaption { padding: 6px 6px 0px; } figure.collage { overflow: hidden; border-radius: 6px; } figure.collage .photo-wrap, figure.collage .video-wrap { position: absolute; } figure.collage .photo-wrap .photo { background-size: cover; } figure.collage .video-wrap video { object-fit: cover; position: absolute; top: 50%; left: 50%; width: auto; height: auto; min-width: 100%; min-height: 100%; transform: translate(-50%, -50%); } figure.collage .video-wrap .video-small, video[autoplay] { pointer-events: none; } figure.table-wrap { overflow: auto; -webkit-overflow-scrolling: touch; } figure.table { display: table-cell; padding: 0 18px; } article ol figure.table-wrap, article ul figure.table-wrap { margin-top: 7px; } article ol figure.table, article ul figure.table { padding: 0; } figure blockquote.embed-post { text-align: left; margin-bottom: 0; } article.rtl figure blockquote.embed-post { text-align: right; } blockquote.embed-post address { margin: 0; padding: 5px 0 9px; overflow: hidden; } blockquote.embed-post address figure { width: 50px; height: 50px; float: left; margin: 0 12px 0 0; background: no-repeat center; background-size: cover; border-radius: 50%; } article.rtl blockquote.embed-post address figure { float: right; margin-left: 12px; margin-right: 0; } blockquote.embed-post address a { display: inline-block; padding-top: 2px; font-size: 17px; font-weight: 600; color: var(--td-window-fg); } blockquote.embed-post address time { display: block; line-height: 19px; } blockquote.embed-post p, blockquote.embed-post blockquote { margin: 0 0 7px; clear: left; } blockquote.embed-post figcaption { padding-left: 0; padding-right: 0; } blockquote.embed-post figure.collage { margin-left: -2px; margin-right: -2px; } blockquote.embed-post footer { margin: 12px 0 0; font-style: normal; } blockquote.embed-post footer hr { display: none; } section.embed-post { display: block; width: auto; height: auto; background: var(--td-box-divider-bg); margin: 0 18px 12px; padding: 24px 18px; text-align: center; } section.embed-post strong { font-size: 21px; font-weight: normal; display: block; color: var(--td-window-sub-text-fg); } section.embed-post small { display: block; color: var(--td-window-sub-text-fg); } section.related { margin: 7px 0 12px; } section.related h4 { font-family: var(--font-sans); font-size: 17px; line-height: 26px; font-weight: 500; display: block; padding: 7px 18px; background: var(--td-box-divider-bg); margin: 0; color: var(--td-window-fg); } section.related a.related-link { display: block; padding: 15px 18px 16px; background: var(--td-window-bg); position: relative; overflow: hidden; } section.related a.related-link:after { content: ''; display: block; border-bottom: 1px solid var(--td-history-to-down-shadow); position: absolute; left: 18px; right: 0; bottom: 0; } section.related a.related-link:last-child:after { border-bottom: 0px; } section.related .related-link-url { display: block; font-size: 15px; line-height: 18px; padding: 7px 0; color: var(--td-window-sub-text-fg); word-break: break-word; } section.related .related-link-thumb { display: inline-block; float: right; width: 87px; height: 87px; border-radius: 4px; background: no-repeat center; background-size: cover; margin-left: 15px; } section.related .related-link-content { display: block; margin: -3px 0; } section.related .related-link-title { font-size: 15px; font-weight: 500; line-height: 18px; display: block; display: -webkit-box; margin-bottom: 4px; max-height: 36px; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; white-space: pre-wrap; color: var(--td-window-fg); } section.related .related-link-desc { font-size: 14px; line-height: 17px; display: block; display: -webkit-box; max-height: 51px; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; white-space: pre-wrap; color: var(--td-window-fg); } section.related .related-link-source { font-size: 13px; line-height: 17px; display: block; overflow: hidden; margin-top: 4px; text-overflow: ellipsis; white-space: nowrap; color: var(--td-window-sub-text-fg); } section.message { position: absolute; display: table; width: 100%; height: 100%; } section.message.static { position: static; min-height: 200px; height: 100vh; } section.message > aside { display: table-cell; vertical-align: middle; text-align: center; color: var(--td-window-sub-text-fg); font-size: 24px; pointer-events: none; } section.message > aside > cite { display: block; font-size: 14px; padding: 10px 0 0; font-style: normal; color: var(--td-window-sub-text-fg); } section.channel { margin-top: -16px; margin-bottom: -9px; } section.channel:first-child { margin-top: 0; } section.channel > a { display: block; background: var(--td-box-divider-bg); } section.channel > a > div.join { color: var(--td-window-active-text-fg); font-weight: 500; padding: 7px 18px; float: right; } section.channel.joined > a > div.join { display: none; } section.channel > a > div.join:hover { text-decoration: underline; } section.channel > a > div.join span:before { content: var(--td-lng-iv-join-channel); } section.channel > a > h4 { font-family: var(--font-sans); font-size: 17px; line-height: 26px; font-weight: 500; margin: 0; color: var(--td-window-fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding: 7px 18px; } .pullquote { text-align: center; max-width: 420px; font-size: 19px; display: block; margin: 0 auto; } .media-outer { margin-bottom: 16px; } .photo-wrap, .video-wrap { width: 100%; margin: 0 auto; position: relative; overflow: hidden; } .photo-bg, .video-bg { background-size: cover; background-position: center; background-repeat: no-repeat; position: absolute; filter: blur(16px); width: 100%; height: 100%; } .video-bg, video { position: absolute; top: 0px; } .photo { position: relative; background-size: contain; background-position: center; background-repeat: no-repeat; } .photo, video { opacity: 0; transition: opacity 300ms ease-in-out; } .photo.loaded, video.loaded { opacity: 1; } .video-play-outer { position: relative; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; } .video-play { position: relative; width: 48px; height: 0; padding-top: 48px; max-width: 48px; max-height: 48px; background-color: rgba(0, 0, 0, 0.34); border-radius: 50%; display: flex; justify-content: center; align-items: center; overflow: hidden; } .video-play::before { content: ''; position: absolute; margin: -48px -4px 0px 0px; width: 0; height: 0; border-style: solid; border-width: 10px 0 10px 16px; border-color: transparent transparent transparent white; } .toast { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: var(--td-toast-bg); color: var(--td-toast-fg); padding: 10px 20px; border-radius: 6px; z-index: 9999; opacity: 0; animation: fadeIn 200ms linear forwards; } .toast.hiding { opacity: 1; animation: fadeOut 1000ms linear forwards; } ================================================ FILE: Telegram/Resources/iv_html/page.js ================================================ var IV = { notify: function(message) { if (window.external && window.external.invoke) { window.external.invoke(JSON.stringify(message)); } }, frameClickHandler: function(e) { var target = e.target; var context = ''; while (target) { if (target.id == 'menu_page_blocker') { IV.notify({ event: 'menu_page_blocker_click' }); IV.menuShown(false); return; } if (target.tagName == 'AUDIO' || target.tagName == 'VIDEO') { return; } if (context === '' && target.hasAttribute && target.hasAttribute('data-context')) { context = String(target.getAttribute('data-context')); } if (target.tagName == 'A') { break; } target = target.parentNode; } if (!target || (context === '' && !target.hasAttribute('href'))) { return; } var base = document.createElement('A'); base.href = window.location.href; if (base.origin != target.origin || base.pathname != target.pathname || base.search != target.search) { IV.notify({ event: 'link_click', url: target.href, context: context, }); } else if (target.hash.length < 2) { IV.jumpToHash(''); } else { IV.jumpToHash(decodeURIComponent(target.hash.substr(1))); } e.preventDefault(); }, getElementTop: function (element) { var top = 0; while (element && !element.classList.contains('page-scroll')) { top += element.offsetTop; element = element.offsetParent; } return top; }, jumpToHash: function (hash, instant) { var current = IV.computeCurrentState(); current.hash = hash; window.history.replaceState( current, '', 'page' + IV.index + '.html'); if (hash == '') { IV.scrollTo(0, instant); return; } var element = document.getElementsByName(hash)[0]; if (element) { IV.scrollTo(IV.getElementTop(element), instant); } }, frameKeyDown: function (e) { const key0 = (e.key === '0') || (e.code === 'Key0') || (e.keyCode === 48); const keyW = (e.key === 'w') || (e.code === 'KeyW') || (e.keyCode === 87); const keyQ = (e.key === 'q') || (e.code === 'KeyQ') || (e.keyCode === 81); const keyM = (e.key === 'm') || (e.code === 'KeyM') || (e.keyCode === 77); if ((e.metaKey || e.ctrlKey) && (keyW || keyQ || keyM || key0)) { e.preventDefault(); IV.notify({ event: 'keydown', modifier: e.ctrlKey ? 'ctrl' : 'cmd', key: key0 ? '0' : keyW ? 'w' : keyQ ? 'q' : 'm', }); } else if (e.key === 'Escape' || e.keyCode === 27) { e.preventDefault(); if (IV.position) { window.history.back(); } else { IV.notify({ event: 'keydown', key: 'escape', }); } } }, frameMouseEnter: function (e) { IV.notify({ event: 'mouseenter' }); }, frameMouseUp: function (e) { IV.notify({ event: 'mouseup' }); }, lastScrollTop: 0, frameScrolled: function (e) { const was = IV.lastScrollTop; IV.lastScrollTop = IV.findPageScroll().scrollTop; IV.updateJumpToTop(was < IV.lastScrollTop); IV.checkVideos(); }, updateJumpToTop: function (scrolledDown) { if (IV.lastScrollTop < 100) { document.getElementById('bottom_up').classList.add('hidden'); } else if (scrolledDown && IV.lastScrollTop > 200) { document.getElementById('bottom_up').classList.remove('hidden'); } }, updateStyles: function (styles) { if (IV.styles !== styles) { IV.styles = styles; document.getElementsByTagName('html')[0].style = styles; } }, toggleChannelJoined: function (id, joined) { IV.channelsJoined['channel' + id] = joined; IV.checkChannelButtons(); }, checkChannelButtons: function() { const channels = document.getElementsByClassName('channel'); for (var i = 0; i < channels.length; ++i) { const channel = channels[i]; const full = String(channel.getAttribute('data-context')); const value = IV.channelsJoined[full]; if (value !== undefined) { channel.classList.toggle('joined', value); } } }, slideshowSlide: function(el, delta) { var dir = window.getComputedStyle(el, null).direction || 'ltr'; var marginProp = dir == 'rtl' ? 'marginRight' : 'marginLeft'; if (delta) { var form = el.parentNode.firstChild; var s = form.s; const next = +s.value + delta; s.value = (next == s.length) ? 0 : (next == -1) ? (s.length - 1) : next; form.nextSibling.firstChild.style[marginProp] = (-100 * s.value) + '%'; } else { el.form.nextSibling.firstChild.style[marginProp] = (-100 * el.value) + '%'; } return false; }, initPreBlocks: function() { if (!window.hljs) { return; } var pres = document.getElementsByTagName('pre'); for (var i = 0; i < pres.length; i++) { if (pres[i].hasAttribute('data-language')) { window.hljs.highlightBlock(pres[i]); } } }, initEmbedBlocks: function() { var iframes = document.getElementsByTagName('iframe'); for (var i = 0; i < iframes.length; i++) { (function(iframe) { window.addEventListener('message', function(event) { if (event.source !== iframe.contentWindow || event.origin != window.origin) { return; } try { var data = JSON.parse(event.data); } catch(e) { var data = {}; } if (data.eventType == 'resize_frame') { if (data.eventData.height) { iframe.style.height = data.eventData.height + 'px'; } } }, false); })(iframes[i]); } }, addRipple: function (button, x, y) { const ripple = document.createElement('span'); ripple.classList.add('ripple'); const inner = document.createElement('span'); inner.classList.add('inner'); x -= button.offsetLeft; y -= button.offsetTop; const mx = button.clientWidth - x; const my = button.clientHeight - y; const sq1 = x * x + y * y; const sq2 = mx * mx + y * y; const sq3 = x * x + my * my; const sq4 = mx * mx + my * my; const radius = Math.sqrt(Math.max(sq1, sq2, sq3, sq4)); inner.style.width = inner.style.height = `${2 * radius}px`; inner.style.left = `${x - radius}px`; inner.style.top = `${y - radius}px`; inner.classList.add('inner'); ripple.addEventListener('animationend', function (e) { if (e.animationName === 'fadeOut') { ripple.remove(); } }); ripple.appendChild(inner); button.appendChild(ripple); }, stopRipples: function (button) { const id = button.id ? button.id : button; button = document.getElementById(id); const ripples = button.getElementsByClassName('ripple'); for (var i = 0; i < ripples.length; ++i) { const ripple = ripples[i]; if (!ripple.classList.contains('hiding')) { ripple.classList.add('hiding'); } } }, init: function () { var current = IV.computeCurrentState(); window.history.replaceState(current, '', IV.pageUrl(0)); IV.jumpToHash(current.hash, true); IV.lastScrollTop = window.history.state.scroll; IV.findPageScroll().onscroll = IV.frameScrolled; const buttons = document.getElementsByClassName('fixed_button'); for (let i = 0; i < buttons.length; ++i) { const button = buttons[i]; button.addEventListener('mousedown', function (e) { IV.addRipple(e.currentTarget, e.clientX, e.clientY); }); button.addEventListener('mouseup', function (e) { const id = e.currentTarget.id; setTimeout(function () { IV.stopRipples(id); }, 0); }); button.addEventListener('mouseleave', function (e) { IV.stopRipples(e.currentTarget); }); } IV.initMedia(); IV.notify({ event: 'ready' }); IV.forceScrollFocus(); IV.frameScrolled(); }, initMedia: function () { var scroll = IV.findPageScroll(); const photos = scroll.getElementsByClassName('photo'); for (let i = 0; i < photos.length; ++i) { const photo = photos[i]; if (photo.classList.contains('loaded')) { continue; } const url = photo.style.backgroundImage; if (!url || url.length < 7) { continue; } var img = new Image(); img.onload = function () { photo.classList.add('loaded'); } img.src = url.substr(5, url.length - 7); if (img.complete) { photo.classList.add('loaded'); IV.stopAnimations(photo); } } IV.videos = []; const videos = scroll.getElementsByClassName('video'); for (let i = 0; i < videos.length; ++i) { const element = videos[i]; IV.videos.push({ element: element, src: String(element.getAttribute('data-src')), autoplay: (element.getAttribute('data-autoplay') == '1'), loop: (element.getAttribute('data-loop') == '1'), small: (element.getAttribute('data-small') == '1'), filled: (element.firstChild && element.firstChild.tagName == 'VIDEO'), }); } }, checkVideos: function () { const visibleTop = IV.lastScrollTop; const visibleBottom = visibleTop + IV.findPageScroll().offsetHeight; const videos = IV.videos; for (let i = 0; i < videos.length; ++i) { const video = videos[i]; const element = video.element; const wrap = element.offsetParent; // video-wrap const top = IV.getElementTop(wrap); const bottom = top + wrap.offsetHeight; if (top < visibleBottom && bottom > visibleTop) { if (!video.created) { video.created = new Date(); video.loaded = false; element.innerHTML = ''; var media = element.firstChild; media.oncontextmenu = function () { return false; }; media.oncanplay = IV.checkVideos; media.onloadeddata = IV.checkVideos; } } else if (video.created && video.autoplay) { video.created = false; element.innerHTML = ''; } if (video.created && !video.loaded) { var media = element.firstChild; const HAVE_CURRENT_DATA = 2; if (media && media.readyState >= HAVE_CURRENT_DATA) { video.loaded = true; media.classList.add('loaded'); if ((new Date() - video.created) < 100) { IV.stopAnimations(media); } } } } }, showTooltip: function (text) { var toast = document.createElement('div'); toast.classList.add('toast'); toast.textContent = text; document.body.appendChild(toast); setTimeout(function () { toast.classList.add('hiding'); }, 2000); setTimeout(function () { document.body.removeChild(toast); }, 3000); }, scrollTo: function (y, instant) { if (y < 200) { document.getElementById('bottom_up').classList.add('hidden'); } IV.findPageScroll().scrollTo({ top: y || 0, behavior: instant ? 'instant' : 'smooth' }); }, computeCurrentState: function () { var now = IV.findPageScroll(); return { position: IV.position, index: IV.index, hash: ((!window.history.state || window.history.state.hash === undefined) ? window.location.hash.substr(1) : window.history.state.hash), scroll: now ? now.scrollTop : 0 }; }, pageUrl: function (index, hash) { var result = 'page' + index + '.html'; if (hash) { result += '#' + hash; } return result; }, navigateTo: function (index, hash) { if (!index && !IV.index) { IV.navigateToDOM(IV.index, hash); return; } IV.pending = [index, hash]; if (!IV.cache[index]) { IV.loadPage(index); } else if (IV.cache[index].dom) { IV.navigateToDOM(index, hash); } else if (IV.cache[index].content) { IV.navigateToLoaded(index, hash); } }, applyUpdatedContent: function (index) { if (IV.index != index) { IV.cache[index].contentUpdated = (IV.cache[index].dom !== undefined); return; } var data = JSON.parse(IV.cache[index].content); var article = function (el) { return el.getElementsByTagName('article')[0]; }; var footer = function (el) { return el.getElementsByClassName('page-footer')[0]; }; var from = IV.findPageScroll(); var to = IV.makeScrolledContent(data.html); morphdom(article(from), article(to), { onBeforeElUpdated: function (fromEl, toEl) { if (fromEl.classList.contains('video') && toEl.classList.contains('video') && fromEl.hasAttribute('data-src') && toEl.hasAttribute('data-src') && (fromEl.getAttribute('data-src') == toEl.getAttribute('data-src'))) { return false; } else if (fromEl.tagName == 'SECTION' && fromEl.classList.contains('channel') && fromEl.hasAttribute('data-context') && toEl.tagName == 'SECTION' && toEl.classList.contains('channel') && toEl.hasAttribute('data-context') && (String(fromEl.getAttribute('data-context')) == String(toEl.getAttribute('data-context')))) { return false; } else if (fromEl.classList.contains('loaded')) { toEl.classList.add('loaded'); } return !fromEl.isEqualNode(toEl); } }); morphdom(footer(from), footer(to)); IV.initMedia(); eval(data.js); }, loadPage: function (index) { if (!IV.cache[index]) { IV.cache[index] = {}; } IV.cache[index].loading = true; let xhr = new XMLHttpRequest(); xhr.onload = function () { IV.cache[index].loading = false; IV.cache[index].content = xhr.responseText; IV.applyUpdatedContent(index); if (IV.pending && IV.pending[0] == index) { IV.navigateToLoaded(index, IV.pending[1]); } if (IV.cache[index].reloadPending) { IV.cache[index].reloadPending = false; IV.reloadPage(index); } } xhr.open('GET', 'page' + index + '.json'); xhr.send(); }, reloadPage: function (index) { if (IV.cache[index] && IV.cache[index].loading) { IV.cache[index].reloadPending = true; return; } IV.loadPage(index); }, makeScrolledContent: function (html) { var result = document.createElement('div'); result.className = 'page-scroll'; result.tabIndex = '-1'; result.innerHTML = html.trim(); result.onscroll = IV.frameScrolled; return result; }, navigateToLoaded: function (index, hash) { if (IV.cache[index].dom) { IV.navigateToDOM(index, hash); } else { var data = JSON.parse(IV.cache[index].content); IV.cache[index].dom = IV.makeScrolledContent(data.html); IV.navigateToDOM(index, hash); eval(data.js); } }, navigateToDOM: function (index, hash) { IV.pending = null; if (IV.index == index) { IV.jumpToHash(hash); IV.forceScrollFocus(); return; } window.history.replaceState( IV.computeCurrentState(), '', IV.pageUrl(IV.index)); IV.position = IV.position + 1; window.history.pushState( { position: IV.position, index: index, hash: hash }, '', IV.pageUrl(index)); IV.showDOM(index, hash); }, findPageScroll: function () { var all = document.getElementsByClassName('page-scroll'); for (i = 0; i < all.length; ++i) { if (!all[i].classList.contains('hidden-left') && !all[i].classList.contains('hidden-right')) { return all[i]; } } return null; }, showDOM: function (index, hash, scroll) { IV.pending = null; if (IV.index != index) { var initial = !window.history.state || window.history.state.position === undefined; var back = initial || IV.position > window.history.state.position; IV.position = initial ? 0 : window.history.state.position; var now = IV.cache[index].dom; var was = IV.findPageScroll(); if (!IV.cache[IV.index]) { IV.cache[IV.index] = {}; } IV.cache[IV.index].dom = was; was.parentNode.appendChild(now); if (scroll !== undefined) { now.scrollTop = scroll; setTimeout(function () { // When returning by history.back to an URL with a hash // for the first time browser forces the scroll to the // hash instead of the saved scroll position. // // This workaround prevents incorrect scroll position. now.scrollTop = scroll; }, 0); } now.classList.add(back ? 'hidden-left' : 'hidden-right'); now.classList.remove(back ? 'hidden-right' : 'hidden-left'); IV.stopAnimations(now.firstChild); if (!was.listening) { was.listening = true; was.firstChild.addEventListener('transitionend', function (e) { if (was.classList.contains('hidden-left') || was.classList.contains('hidden-right')) { if (was.parentNode) { was.parentNode.removeChild(was); var videos = was.getElementsByClassName('video'); for (var i = 0; i < videos.length; ++i) { videos[i].innerHTML = ''; } } } }); } was.classList.add(back ? 'hidden-right' : 'hidden-left'); now.classList.remove(back ? 'hidden-left' : 'hidden-right'); IV.index = index; IV.notify({ event: 'location_change', index: IV.index, position: IV.position, hash: IV.computeCurrentState().hash, }); if (IV.cache[index].contentUpdated) { IV.cache[index].contentUpdated = false; IV.applyUpdatedContent(index); } else { IV.initMedia(); } IV.checkChannelButtons(); if (scroll === undefined) { IV.jumpToHash(hash, true); } else { IV.lastScrollTop = scroll; IV.updateJumpToTop(true); } } else if (scroll !== undefined) { IV.scrollTo(scroll); IV.lastScrollTop = scroll; IV.updateJumpToTop(true); } else { IV.jumpToHash(hash); } IV.forceScrollFocus(); IV.frameScrolled(); }, forceScrollFocus: function () { IV.findPageScroll().focus(); setTimeout(function () { // Doesn't work on #hash-ed pages in Windows WebView2 otherwise. IV.findPageScroll().focus(); }, 100); }, stopAnimations: function (element) { element.getAnimations().forEach( (animation) => animation.finish()); }, menuShown: function (shown) { var already = document.getElementById('menu_page_blocker'); if (already && shown) { return; } else if (already) { document.body.removeChild(already); return; } else if (!shown) { return; } var blocker = document.createElement('div'); blocker.id = 'menu_page_blocker'; document.body.appendChild(blocker); }, videos: {}, videosPlaying: {}, cache: {}, channelsJoined: {}, index: 0, position: 0 }; document.onclick = IV.frameClickHandler; document.onkeydown = IV.frameKeyDown; document.onmouseenter = IV.frameMouseEnter; document.onmouseup = IV.frameMouseUp; document.onresize = IV.checkVideos; window.onmessage = IV.postMessageHandler; window.addEventListener('popstate', function (e) { if (e.state) { IV.showDOM(e.state.index, e.state.hash, e.state.scroll); } }); document.addEventListener("DOMContentLoaded", IV.forceScrollFocus); ================================================ FILE: Telegram/Resources/langs/cloud_lang.strings ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ "cloud_lng_badge_psa_covid" = "COVID-19"; "cloud_lng_about_psa_covid" = "This message provides you with a public service announcement in relation to the ongoing COVID-19 pandemic. To remove it from your chats list, right click it and select **Hide**."; "cloud_lng_forwarded_psa_covid" = "COVID-19 Notification from {channel}"; "cloud_lng_tooltip_psa_covid" = "This message provides you with a public service announcement in relation to the ongoing COVID-19 pandemic. Learn more about this initiative at https://telegram.org/blog/coronavirus"; "cloud_lng_topup_purpose_subs" = "Buy **Stars** to keep your channel subscriptions."; "cloud_lng_age_verify_about_gb#one" = "To access such content, you must confirm that you are at least **{count}** year old as required by UK law."; "cloud_lng_age_verify_about_gb#other" = "To access such content, you must confirm that you are at least **{count}** years old as required by UK law."; "cloud_lng_passport_in_ar" = "Arabic"; "cloud_lng_passport_in_az" = "Azerbaijani"; "cloud_lng_passport_in_bg" = "Bulgarian"; "cloud_lng_passport_in_bn" = "Bengali"; "cloud_lng_passport_in_cs" = "Czech"; "cloud_lng_passport_in_da" = "Danish"; "cloud_lng_passport_in_de" = "German"; "cloud_lng_passport_in_dv" = "Divehi"; "cloud_lng_passport_in_dz" = "Dzongkha"; "cloud_lng_passport_in_el" = "Greek"; "cloud_lng_passport_in_en" = "English"; "cloud_lng_passport_in_es" = "Spanish"; "cloud_lng_passport_in_et" = "Estonian"; "cloud_lng_passport_in_fa" = "Persian"; "cloud_lng_passport_in_fr" = "French"; "cloud_lng_passport_in_he" = "Hebrew"; "cloud_lng_passport_in_hr" = "Croatian"; "cloud_lng_passport_in_hu" = "Hungarian"; "cloud_lng_passport_in_hy" = "Armenian"; "cloud_lng_passport_in_id" = "Indonesian"; "cloud_lng_passport_in_is" = "Icelandic"; "cloud_lng_passport_in_it" = "Italian"; "cloud_lng_passport_in_ja" = "Japanese"; "cloud_lng_passport_in_ka" = "Georgian"; // "cloud_lng_passport_in_km" = "Khmer"; "cloud_lng_passport_in_ko" = "Korean"; "cloud_lng_passport_in_lo" = "Lao"; "cloud_lng_passport_in_lt" = "Lithuanian"; "cloud_lng_passport_in_lv" = "Latvian"; "cloud_lng_passport_in_mk" = "Macedonian"; "cloud_lng_passport_in_mn" = "Mongolian"; "cloud_lng_passport_in_ms" = "Malay"; "cloud_lng_passport_in_my" = "Burmese"; "cloud_lng_passport_in_ne" = "Nepali"; "cloud_lng_passport_in_nl" = "Dutch"; "cloud_lng_passport_in_pl" = "Polish"; "cloud_lng_passport_in_pt" = "Portuguese"; "cloud_lng_passport_in_ro" = "Romanian"; "cloud_lng_passport_in_ru" = "Russian"; "cloud_lng_passport_in_sk" = "Slovak"; "cloud_lng_passport_in_sl" = "Slovenian"; "cloud_lng_passport_in_th" = "Thai"; "cloud_lng_passport_in_tk" = "Turkmen"; "cloud_lng_passport_in_tr" = "Turkish"; "cloud_lng_passport_in_uk" = "Ukrainian"; "cloud_lng_passport_in_uz" = "Uzbek"; "cloud_lng_passport_in_vi" = "Vietnamese"; "cloud_lng_translate_to_ar" = "Arabic"; "cloud_lng_translate_to_az" = "Azerbaijani"; "cloud_lng_translate_to_bg" = "Bulgarian"; // "cloud_lng_translate_to_bn" = "Bengali"; "cloud_lng_translate_to_cs" = "Czech"; "cloud_lng_translate_to_da" = "Danish"; "cloud_lng_translate_to_de" = "German"; // "cloud_lng_translate_to_dv" = "Divehi"; // "cloud_lng_translate_to_dz" = "Dzongkha"; "cloud_lng_translate_to_el" = "Greek"; "cloud_lng_translate_to_en" = "English"; "cloud_lng_translate_to_es" = "Spanish"; "cloud_lng_translate_to_et" = "Estonian"; "cloud_lng_translate_to_fa" = "Persian"; "cloud_lng_translate_to_fr" = "French"; "cloud_lng_translate_to_he" = "Hebrew"; "cloud_lng_translate_to_hr" = "Croatian"; "cloud_lng_translate_to_hu" = "Hungarian"; "cloud_lng_translate_to_hy" = "Armenian"; "cloud_lng_translate_to_id" = "Indonesian"; "cloud_lng_translate_to_is" = "Icelandic"; "cloud_lng_translate_to_it" = "Italian"; "cloud_lng_translate_to_ja" = "Japanese"; "cloud_lng_translate_to_ka" = "Georgian"; // "cloud_lng_translate_to_km" = "Khmer"; "cloud_lng_translate_to_ko" = "Korean"; "cloud_lng_translate_to_lo" = "Lao"; "cloud_lng_translate_to_lt" = "Lithuanian"; "cloud_lng_translate_to_lv" = "Latvian"; "cloud_lng_translate_to_mk" = "Macedonian"; "cloud_lng_translate_to_mn" = "Mongolian"; "cloud_lng_translate_to_ms" = "Malay"; "cloud_lng_translate_to_my" = "Burmese"; "cloud_lng_translate_to_ne" = "Nepali"; "cloud_lng_translate_to_nl" = "Dutch"; "cloud_lng_translate_to_pl" = "Polish"; "cloud_lng_translate_to_pt" = "Portuguese"; "cloud_lng_translate_to_ro" = "Romanian"; "cloud_lng_translate_to_ru" = "Russian"; "cloud_lng_translate_to_sk" = "Slovak"; "cloud_lng_translate_to_sl" = "Slovenian"; "cloud_lng_translate_to_th" = "Thai"; "cloud_lng_translate_to_tk" = "Turkmen"; "cloud_lng_translate_to_tr" = "Turkish"; "cloud_lng_translate_to_uk" = "Ukrainian"; "cloud_lng_translate_to_uz" = "Uzbek"; "cloud_lng_translate_to_vi" = "Vietnamese"; "cloud_lng_language_af" = "Afrikaans"; "cloud_lng_language_am" = "Amharic"; "cloud_lng_language_ar" = "Arabic"; "cloud_lng_language_az" = "Azerbaijani"; "cloud_lng_language_be" = "Belarusian"; "cloud_lng_language_bg" = "Bulgarian"; "cloud_lng_language_bn" = "Bengali"; "cloud_lng_language_bs" = "Bosnian"; "cloud_lng_language_ca" = "Catalan"; // "cloud_lng_language_ceb" = "Cebuano"; "cloud_lng_language_co" = "Corsican"; "cloud_lng_language_cs" = "Czech"; "cloud_lng_language_cy" = "Welsh"; "cloud_lng_language_da" = "Danish"; "cloud_lng_language_de" = "German"; "cloud_lng_language_dv" = "Divehi"; "cloud_lng_language_dz" = "Dzongkha"; "cloud_lng_language_el" = "Greek"; "cloud_lng_language_en" = "English"; "cloud_lng_language_eo" = "Esperanto"; "cloud_lng_language_es" = "Spanish"; "cloud_lng_language_et" = "Estonian"; "cloud_lng_language_eu" = "Basque"; "cloud_lng_language_fa" = "Persian"; "cloud_lng_language_fi" = "Finnish"; "cloud_lng_language_fr" = "French"; "cloud_lng_language_fy" = "Frisian"; "cloud_lng_language_ga" = "Irish"; "cloud_lng_language_gd" = "Scots Gaelic"; "cloud_lng_language_gl" = "Galician"; "cloud_lng_language_gu" = "Gujarati"; "cloud_lng_language_ha" = "Hausa"; "cloud_lng_language_haw" = "Hawaiian"; "cloud_lng_language_he" = "Hebrew"; "cloud_lng_language_hi" = "Hindi"; // "cloud_lng_language_hmn" = "Hmong"; "cloud_lng_language_hr" = "Croatian"; "cloud_lng_language_ht" = "Haitian Creole"; "cloud_lng_language_hu" = "Hungarian"; "cloud_lng_language_hy" = "Armenian"; "cloud_lng_language_id" = "Indonesian"; "cloud_lng_language_ig" = "Igbo"; "cloud_lng_language_is" = "Icelandic"; "cloud_lng_language_it" = "Italian"; "cloud_lng_language_iw" = "Hebrew (Obsolete code)"; "cloud_lng_language_ja" = "Japanese"; "cloud_lng_language_jv" = "Javanese"; "cloud_lng_language_ka" = "Georgian"; "cloud_lng_language_kk" = "Kazakh"; "cloud_lng_language_km" = "Khmer"; "cloud_lng_language_kn" = "Kannada"; "cloud_lng_language_ko" = "Korean"; "cloud_lng_language_ku" = "Kurdish"; "cloud_lng_language_ky" = "Kyrgyz"; "cloud_lng_language_la" = "Latin"; "cloud_lng_language_lb" = "Luxembourgish"; "cloud_lng_language_lo" = "Lao"; "cloud_lng_language_lt" = "Lithuanian"; "cloud_lng_language_lv" = "Latvian"; "cloud_lng_language_mg" = "Malagasy"; "cloud_lng_language_mi" = "Maori"; "cloud_lng_language_mk" = "Macedonian"; "cloud_lng_language_ml" = "Malayalam"; "cloud_lng_language_mn" = "Mongolian"; "cloud_lng_language_mr" = "Marathi"; "cloud_lng_language_ms" = "Malay"; "cloud_lng_language_mt" = "Maltese"; "cloud_lng_language_my" = "Burmese"; "cloud_lng_language_ne" = "Nepali"; "cloud_lng_language_nl" = "Dutch"; "cloud_lng_language_no" = "Norwegian"; "cloud_lng_language_ny" = "Nyanja"; "cloud_lng_language_or" = "Odia (Oriya)"; "cloud_lng_language_pa" = "Punjabi"; "cloud_lng_language_pl" = "Polish"; "cloud_lng_language_ps" = "Pashto"; "cloud_lng_language_pt" = "Portuguese"; "cloud_lng_language_ro" = "Romanian"; "cloud_lng_language_ru" = "Russian"; "cloud_lng_language_rw" = "Kinyarwanda"; "cloud_lng_language_sd" = "Sindhi"; "cloud_lng_language_si" = "Sinhala"; "cloud_lng_language_sk" = "Slovak"; "cloud_lng_language_sl" = "Slovenian"; "cloud_lng_language_sm" = "Samoan"; "cloud_lng_language_sn" = "Shona"; "cloud_lng_language_so" = "Somali"; "cloud_lng_language_sq" = "Albanian"; "cloud_lng_language_sr" = "Serbian"; "cloud_lng_language_st" = "Sesotho"; "cloud_lng_language_su" = "Sundanese"; "cloud_lng_language_sv" = "Swedish"; "cloud_lng_language_sw" = "Swahili"; "cloud_lng_language_ta" = "Tamil"; "cloud_lng_language_te" = "Telugu"; "cloud_lng_language_tg" = "Tajik"; "cloud_lng_language_th" = "Thai"; "cloud_lng_language_tk" = "Turkmen"; "cloud_lng_language_tl" = "Tagalog"; "cloud_lng_language_tr" = "Turkish"; "cloud_lng_language_tt" = "Tatar"; "cloud_lng_language_ug" = "Uyghur"; "cloud_lng_language_uk" = "Ukrainian"; "cloud_lng_language_ur" = "Urdu"; "cloud_lng_language_uz" = "Uzbek"; "cloud_lng_language_vi" = "Vietnamese"; "cloud_lng_language_xh" = "Xhosa"; "cloud_lng_language_yi" = "Yiddish"; "cloud_lng_language_yo" = "Yoruba"; "cloud_lng_language_zh" = "Chinese"; // "cloud_lng_language_zh-CN" = "Chinese (Simplified)"; // "cloud_lng_language_zh-TW" = "Chinese (Traditional)"; "cloud_lng_language_zu" = "Zulu"; ================================================ FILE: Telegram/Resources/langs/de.lproj/Localizable.strings ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ ================================================ FILE: Telegram/Resources/langs/en.lproj/Localizable.strings ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ ================================================ FILE: Telegram/Resources/langs/es.lproj/Localizable.strings ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ ================================================ FILE: Telegram/Resources/langs/it.lproj/Localizable.strings ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ ================================================ FILE: Telegram/Resources/langs/ko.lproj/Localizable.strings ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ ================================================ FILE: Telegram/Resources/langs/lang.strings ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ "lng_language_name" = "English"; "lng_switch_to_this" = "Continue in English"; "lng_menu_contacts" = "Contacts"; "lng_menu_calls" = "Calls"; "lng_menu_settings" = "Settings"; "lng_menu_about" = "About"; "lng_menu_update" = "Update"; "lng_menu_night_mode" = "Night Mode"; "lng_menu_add_account" = "Add Account"; "lng_menu_activate" = "Use this account"; "lng_menu_set_status" = "Set Emoji Status"; "lng_menu_change_status" = "Change Emoji Status"; "lng_menu_my_profile" = "My Profile"; "lng_menu_my_stories" = "My Stories"; "lng_menu_my_groups" = "My Groups"; "lng_menu_my_channels" = "My Channels"; "lng_main_menu" = "Main menu"; "lng_filter_unread_chats#one" = "{text} ({count} unread chat)"; "lng_filter_unread_chats#other" = "{text} ({count} unread chats)"; "lng_disable_notifications_from_tray" = "Disable notifications"; "lng_enable_notifications_from_tray" = "Enable notifications"; "lng_open_from_tray" = "Open Telegram"; "lng_minimize_to_tray" = "Minimize to Tray"; "lng_quit_from_tray" = "Quit Telegram"; "lng_tray_icon_text" = "Telegram is still running here,\nyou can change this in Settings.\nIf it disappears from the tray,\nyou can drag it back from the hidden icons."; // For lng_month_year or plain month name. "lng_month1" = "January"; "lng_month2" = "February"; "lng_month3" = "March"; "lng_month4" = "April"; "lng_month5" = "May"; "lng_month6" = "June"; "lng_month7" = "July"; "lng_month8" = "August"; "lng_month9" = "September"; "lng_month10" = "October"; "lng_month11" = "November"; "lng_month12" = "December"; // For lng_month_day and lng_month_day_year. "lng_month_day1" = "January"; "lng_month_day2" = "February"; "lng_month_day3" = "March"; "lng_month_day4" = "April"; "lng_month_day5" = "May"; "lng_month_day6" = "June"; "lng_month_day7" = "July"; "lng_month_day8" = "August"; "lng_month_day9" = "September"; "lng_month_day10" = "October"; "lng_month_day11" = "November"; "lng_month_day12" = "December"; "lng_month1_small" = "Jan"; "lng_month2_small" = "Feb"; "lng_month3_small" = "Mar"; "lng_month4_small" = "Apr"; "lng_month5_small" = "May"; "lng_month6_small" = "Jun"; "lng_month7_small" = "Jul"; "lng_month8_small" = "Aug"; "lng_month9_small" = "Sep"; "lng_month10_small" = "Oct"; "lng_month11_small" = "Nov"; "lng_month12_small" = "Dec"; "lng_weekday1" = "Mon"; "lng_weekday2" = "Tue"; "lng_weekday3" = "Wed"; "lng_weekday4" = "Thu"; "lng_weekday5" = "Fri"; "lng_weekday6" = "Sat"; "lng_weekday7" = "Sun"; "lng_month_day" = "{month} {day}"; "lng_month_day_year" = "{month} {day}, {year}"; "lng_month_year" = "{month} {year}"; "lng_calendar_select_days" = "Select days"; "lng_calendar_start_tip" = "Press and hold to jump to the start."; "lng_calendar_end_tip" = "Press and hold to jump to the end."; "lng_calendar_days#one" = "{count} day"; "lng_calendar_days#other" = "{count} days"; "lng_seconds#one" = "{count} second"; "lng_seconds#other" = "{count} seconds"; "lng_minutes#one" = "{count} minute"; "lng_minutes#other" = "{count} minutes"; "lng_hours#one" = "{count} hour"; "lng_hours#other" = "{count} hours"; "lng_days#one" = "{count} day"; "lng_days#other" = "{count} days"; "lng_weeks#one" = "{count} week"; "lng_weeks#other" = "{count} weeks"; "lng_months#one" = "{count} month"; "lng_months#other" = "{count} months"; "lng_years#one" = "{count} year"; "lng_years#other" = "{count} years"; "lng_seconds_tiny#one" = "{count}s"; "lng_seconds_tiny#other" = "{count}s"; "lng_minutes_tiny#one" = "{count}m"; "lng_minutes_tiny#other" = "{count}m"; "lng_hours_tiny#one" = "{count}h"; "lng_hours_tiny#other" = "{count}h"; "lng_days_tiny#one" = "{count}d"; "lng_days_tiny#other" = "{count}d"; "lng_weeks_tiny#one" = "{count}w"; "lng_weeks_tiny#other" = "{count}w"; "lng_months_tiny#one" = "{count}m"; "lng_months_tiny#other" = "{count}m"; "lng_years_tiny#one" = "{count}y"; "lng_years_tiny#other" = "{count}y"; "lng_box_ok" = "OK"; "lng_box_done" = "Done"; "lng_box_yes" = "Yes"; "lng_box_no" = "No"; "lng_cancel" = "Cancel"; "lng_continue" = "Continue"; "lng_close" = "Close"; "lng_minimize_window" = "Minimize"; "lng_maximize_window" = "Maximize"; "lng_restore_window" = "Restore"; "lng_go_back" = "Go back"; "lng_connecting" = "Connecting..."; "lng_reconnecting#one" = "Reconnect in {count} s..."; "lng_reconnecting#other" = "Reconnect in {count} s..."; "lng_reconnecting_try_now" = "Try now"; "lng_code_block_header_copy" = "copy"; "lng_status_service_notifications" = "service notifications"; "lng_status_support" = "support"; "lng_status_bot" = "bot"; "lng_status_bot_reads_all" = "has access to messages"; "lng_status_bot_not_reads_all" = "has no access to messages"; "lng_status_offline" = "last seen a long time ago"; "lng_status_recently" = "last seen recently"; "lng_status_last_week" = "last seen within a week"; "lng_status_last_month" = "last seen within a month"; "lng_status_lastseen_now" = "last seen just now"; "lng_status_lastseen_when" = "when?"; "lng_status_lastseen_minutes#one" = "last seen {count} minute ago"; "lng_status_lastseen_minutes#other" = "last seen {count} minutes ago"; "lng_status_lastseen_hours#one" = "last seen {count} hour ago"; "lng_status_lastseen_hours#other" = "last seen {count} hours ago"; "lng_status_lastseen_today" = "last seen today at {time}"; "lng_status_lastseen_yesterday" = "last seen yesterday at {time}"; "lng_status_lastseen_date" = "last seen {date}"; "lng_status_lastseen_date_time" = "last seen {date} at {time}"; "lng_status_online" = "online"; "lng_status_connecting" = "connecting..."; "lng_chat_status_unaccessible" = "group is inaccessible"; "lng_chat_status_members#one" = "{count} member"; "lng_chat_status_members#other" = "{count} members"; "lng_chat_status_online#one" = "{count} online"; "lng_chat_status_online#other" = "{count} online"; "lng_chat_status_members_online" = "{members_count}, {online_count}"; "lng_chat_status_subscribers#one" = "{count} subscriber"; "lng_chat_status_subscribers#other" = "{count} subscribers"; "lng_chat_status_direct" = "Direct messages"; "lng_channel_status" = "channel"; "lng_group_status" = "group"; "lng_scam_badge" = "SCAM"; "lng_fake_badge" = "FAKE"; "lng_direct_badge" = "DIRECT"; "lng_remember" = "Remember this choice"; "lng_lastseen_show_title" = "Show Your Last Seen"; "lng_lastseen_show_about" = "To see **{user}'s** Last Seen time, either start\nshowing your own Last Seen time..."; "lng_lastseen_show_button" = "Show My Last Seen"; "lng_lastseen_or" = "or"; "lng_lastseen_premium_title" = "Upgrade to Premium"; "lng_lastseen_premium_about" = "Subscribing will let you see **{user}'s** Last Seen\nstatus without showing yours."; "lng_lastseen_premium_button" = "Subscribe to Telegram Premium"; "lng_lastseen_shown_toast" = "Your last seen time is now visible."; "lng_readtime_show_title" = "Show Your Read Date"; "lng_readtime_show_about" = "To see when **{user}** read the message,\neither start showing your own read time..."; "lng_readtime_show_button" = "Show My Read Time"; "lng_readtime_or" = "or"; "lng_readtime_premium_title" = "Upgrade to Premium"; "lng_readtime_premium_about" = "Subscription will let you see **{user}'s** read time\nwithout showing yours."; "lng_readtime_premium_button" = "Subscribe to Telegram Premium"; "lng_readtime_shown_toast" = "Your read times are now visible."; "lng_channels_limit_title" = "Too Many Communities"; "lng_channels_limit1#one" = "You are a member of **{count}** group or channel."; "lng_channels_limit1#other" = "You are a member of **{count}** groups and channels."; "lng_channels_limit2#one" = "Please leave some before joining a new one — or upgrade to **Telegram Premium** to double the limit to **{count}** group or channel."; "lng_channels_limit2#other" = "Please leave some before joining a new one — or upgrade to **Telegram Premium** to double the limit to **{count}** groups and channels."; "lng_channels_limit2_final" = "Please leave some before joining a new one."; "lng_channels_leave_title" = "Least active communities"; "lng_channels_leave_status" = "{type}, inactive {time}"; "lng_channels_leave#one" = "Leave {count} community"; "lng_channels_leave#other" = "Leave {count} communities"; "lng_channels_leave_done" = "You've left the selected communities."; "lng_links_limit_title" = "Too Many Public Links"; "lng_links_limit1#one" = "You have reserved **{count}** public link."; "lng_links_limit1#other" = "You have reserved **{count}** public links."; "lng_links_limit2#one" = "Try revoking the link from an older group or channel, or subscribe to **Telegram Premium** to double the limit to **{count}** public link."; "lng_links_limit2#other" = "Try revoking the link from an older group or channel, or subscribe to **Telegram Premium** to double the limit to **{count}** public links."; "lng_links_limit2_final" = "Try revoking the link from an older group or channel"; "lng_links_revoke_title" = "Your public communities"; "lng_filter_chats_limit_title" = "Limit Reached"; "lng_filter_chats_limit1#one" = "Sorry, you can't add more than **{count}** chat to a folder."; "lng_filter_chats_limit1#other" = "Sorry, you can't add more than **{count}** chats to a folder."; "lng_filter_chats_exlude_limit1#one" = "Sorry, you can't exclude more than **{count}** chat from a folder."; "lng_filter_chats_exlude_limit1#other" = "Sorry, you can't exclude more than **{count}** chats from a folder."; "lng_filter_chats_limit2#one" = "You can increase this limit to **{count}** by subscribing to **Telegram Premium**."; "lng_filter_chats_limit2#other" = "You can increase this limit to **{count}** by subscribing to **Telegram Premium**."; "lng_filters_limit_title" = "Limit Reached"; "lng_filters_limit1#one" = "You have reached the limit of **{count}** folder."; "lng_filters_limit1#other" = "You have reached the limit of **{count}** folders."; "lng_filters_limit2#one" = "You can double the limit to **{count}** folder by subscribing to **Telegram Premium**."; "lng_filters_limit2#other" = "You can double the limit to **{count}** folders by subscribing to **Telegram Premium**."; "lng_filter_pin_limit_title" = "Limit Reached"; "lng_filter_pin_limit1#one" = "Sorry, you can't pin more than **{count}** chat to the top."; "lng_filter_pin_limit1#other" = "Sorry, you can't pin more than **{count}** chats to the top."; "lng_filter_pin_limit2#one" = "Unpin some of the currently pinned ones or subscribe to **Telegram Premium** to double the limit to **{count}** chat."; "lng_filter_pin_limit2#other" = "Unpin some of the currently pinned ones or subscribe to **Telegram Premium** to double the limit to **{count}** chats."; "lng_forum_pin_limit#one" = "Sorry, you can't pin more than **{count}** topic to the top."; "lng_forum_pin_limit#other" = "Sorry, you can't pin more than **{count}** topics to the top."; "lng_fave_sticker_limit_title#one" = "Limit of {count} Sticker Reached"; "lng_fave_sticker_limit_title#other" = "Limit of {count} Stickers Reached"; "lng_fave_sticker_limit_more#one" = "An older sticker was replaced with this one.\nYou can {link} to {count} sticker."; "lng_fave_sticker_limit_more#other" = "An older sticker was replaced with this one.\nYou can {link} to {count} stickers."; "lng_fave_sticker_limit_link" = "increase the limit"; "lng_saved_gif_limit_title#one" = "Limit of {count} GIF Reached"; "lng_saved_gif_limit_title#other" = "Limit of {count} GIFs Reached"; "lng_saved_gif_limit_more#one" = "An older GIF was replaced with this one.\nYou can {link} to {count} GIF."; "lng_saved_gif_limit_more#other" = "An older GIF was replaced with this one.\nYou can {link} to {count} GIFs."; "lng_saved_gif_limit_link" = "increase the limit"; "lng_caption_limit_title" = "Limit Reached"; "lng_caption_limit1#one" = "Sorry, you can't use more than **{count}** character in media captions."; "lng_caption_limit1#other" = "Sorry, you can't use more than **{count}** characters in media captions."; "lng_caption_limit2#one" = "Make the caption shorter or subscribe to **Telegram Premium** to double the limit to **{count}** character."; "lng_caption_limit2#other" = "Make the caption shorter or subscribe to **Telegram Premium** to double the limit to **{count}** characters."; "lng_caption_limit_reached#one" = "You've reached the media caption limit. Please make the caption shorter by {count} character."; "lng_caption_limit_reached#other" = "You've reached the media caption limit. Please make the caption shorter by {count} characters."; "lng_caption_move_up" = "Move Caption Up"; "lng_caption_move_down" = "Move Caption Down"; "lng_file_size_limit_title" = "File Too Large"; "lng_file_size_limit#one" = "{count} GB"; "lng_file_size_limit#other" = "{count} GB"; "lng_file_size_limit1" = "The document can't be sent, because it is larger than {size}."; "lng_file_size_limit2" = "You can double this limit to {size} per document by subscribing to **Telegram Premium**."; "lng_filter_links_limit_title" = "Limit Reached"; "lng_filter_links_limit1#one" = "Sorry, you can't create more than **{count}** invite link."; "lng_filter_links_limit1#other" = "Sorry, you can't create more than **{count}** invite links."; "lng_filter_links_limit2#one" = "You can increase the limit to **{count}** link by subscribing to **Telegram Premium**."; "lng_filter_links_limit2#other" = "You can increase the limit to **{count}** links by subscribing to **Telegram Premium**."; "lng_filter_shared_limit_title" = "Limit Reached"; "lng_filter_shared_limit1#one" = "Sorry, you can't add more than **{count}** shareable folders."; "lng_filter_shared_limit1#other" = "Sorry, you can't add more than **{count}** shareable folders."; "lng_filter_shared_limit2#one" = "You can increase the limit to **{count}** folder by subscribing to **Telegram Premium**."; "lng_filter_shared_limit2#other" = "You can increase the limit to **{count}** folders by subscribing to **Telegram Premium**."; "lng_limits_increase" = "Increase Limit"; "lng_sticker_premium_text" = "This set contains premium stickers like this one."; "lng_sticker_premium_view" = "View"; "lng_animated_emoji_text" = "Subscribe to **Telegram Premium** to unlock this emoji."; "lng_animated_emoji_saved" = "Try sending these emoji in **Saved Messages** for free to test."; "lng_animated_emoji_saved_open" = "Open"; "lng_flood_error" = "Too many tries. Please try again later."; "lng_edit_error" = "You can't edit this message."; "lng_error_phone_flood" = "Sorry, you have deleted and re-created your account too many times recently. Please wait for a few days before signing up again."; "lng_error_start_minimized_passcoded" = "You have set a local passcode, so Telegram Desktop can't be launched minimized; it will ask you to enter your passcode before it can start working."; "lng_error_public_groups_denied" = "Unfortunately, you are banned from participating in public groups.\n{more_info}"; "lng_error_cant_add_member" = "Sorry, you can't add the bot to this group. Ask a group admin to do it."; "lng_error_cant_add_bot" = "Sorry, this bot can't be added to groups."; "lng_error_cant_add_admin_invite" = "You can't add this user as an admin because they are not a member of this group and you are not allowed to add them."; "lng_error_you_blocked_user" = "Sorry, you can't add this user or bot to groups because you've blocked them. Please unblock to proceed."; "lng_error_add_admin_not_member" = "You can't add this user as an admin because they are not a member of this group and you are not allowed to add them."; "lng_error_user_admin_invalid" = "You can't ban this user because they are an admin in this group and you are not allowed to demote them."; "lng_error_channel_bots_too_much" = "Sorry, this channel has too many bots."; "lng_error_group_bots_too_much" = "There are too many bots in this group. Please remove some of the bots you're not using first."; "lng_error_cant_add_admin_unban" = "Sorry, you can't add this user as an admin because they are in the Removed Users list and you can't unban them."; "lng_error_cant_ban_admin" = "You can't ban this user because they are an admin in this group and you are not allowed to demote them."; "lng_error_cant_reply_other" = "This message can't be replied in another chat."; "lng_error_admin_limit" = "Sorry, you've reached the maximum number of admins for this group."; "lng_error_admin_limit_channel" = "Sorry, you've reached the maximum number of admins for this channel."; "lng_error_post_link_invalid" = "Unfortunately, you can't access this message. You aren't a member of the chat where it was posted."; "lng_error_noforwards_group" = "Sorry, forwarding from this group is disabled by admins."; "lng_error_noforwards_channel" = "Sorry, forwarding from this channel is disabled by admins."; "lng_error_nocopy_group" = "Sorry, copying from this group is disabled by admins."; "lng_error_nocopy_channel" = "Sorry, copying from this channel is disabled by admins."; "lng_error_noforwards_user" = "Sorry, forwarding from this chat is restricted."; "lng_error_nocopy_user" = "Sorry, copying from this chat is restricted."; "lng_error_nocopy_story" = "Sorry, the creator of this story disabled copying."; "lng_error_schedule_limit" = "Sorry, you can't schedule more than 100 messages."; "lng_sure_add_admin_invite" = "This user is not a member of this group. Add them to the group and promote them to admin?"; "lng_sure_add_admin_invite_channel" = "This user is not a subscriber of this channel. Add them to the channel and promote them to admin?"; "lng_sure_add_admin_unremove" = "This user is currently restricted or removed. Are you sure you want to promote them?"; "lng_sure_ban_admin" = "This user is an admin. Are you sure you want to go ahead and restrict them?"; "lng_sure_enable_socks" = "Are you sure you want to enable this proxy?\n\nServer: {server}\nPort: {port}\n\nYou can change your proxy server later in Settings > Advanced > Connection Type."; "lng_sure_enable" = "Enable"; "lng_proxy_box_title" = "Enable proxy"; "lng_proxy_box_table_title" = "Proxy Server"; "lng_proxy_box_table_button" = "Connect Proxy"; "lng_proxy_box_table_checking" = "Checking…"; "lng_proxy_box_table_available" = "Available (ping: {ping} ms)"; "lng_proxy_box_table_unavailable" = "Not Available"; "lng_proxy_box_server" = "Server"; "lng_proxy_box_port" = "Port"; "lng_proxy_box_secret" = "Secret"; "lng_proxy_box_status" = "Status"; "lng_proxy_box_check_status" = "Check Status"; "lng_proxy_box_username" = "Username"; "lng_proxy_box_password" = "Password"; "lng_proxy_invalid" = "The proxy link is invalid."; "lng_proxy_unsupported" = "Your Telegram Desktop version doesn't support this proxy type or the proxy link is invalid. Please update Telegram Desktop to the latest version."; "lng_proxy_incorrect_secret" = "This proxy link uses invalid **secret** parameter. Please contact the proxy provider and ask him to update MTProxy source code and configure it with a correct **secret** value. Then let him provide a new link."; "lng_proxy_check_ip_warning_title" = "Warning"; "lng_proxy_check_ip_warning" = "This will expose your IP address to the admin of the proxy server."; "lng_proxy_check_ip_proceed" = "Proceed"; "lng_edit_deleted" = "This message was deleted"; "lng_edit_limit_reached#one" = "You've reached the message text limit. Please make the text shorter by {count} character."; "lng_edit_limit_reached#other" = "You've reached the message text limit. Please make the text shorter by {count} characters."; "lng_edit_message" = "Edit message"; "lng_edit_message_text" = "New message..."; "lng_deleted" = "Deleted Account"; "lng_deleted_message" = "Deleted message"; "lng_deleted_story" = "Deleted story"; "lng_pinned_message" = "Pinned message"; "lng_pinned_previous" = "Previous message"; "lng_pinned_unpin_sure" = "Would you like to unpin this message?"; "lng_pinned_pin_sure" = "Would you like to pin this message?"; "lng_pinned_pin_sure_group" = "Pin this message in the group?"; "lng_pinned_pin_old_sure" = "Do you want to pin an older message while leaving a more recent one pinned?"; "lng_pinned_pin" = "Pin"; "lng_pinned_unpin" = "Unpin"; "lng_pinned_notify" = "Notify all members"; "lng_pinned_also_for_other" = "Also pin for {user}"; "lng_pinned_messages_title#one" = "{count} pinned message"; "lng_pinned_messages_title#other" = "{count} pinned messages"; "lng_pinned_hide_all" = "Don't show pinned messages"; "lng_pinned_unpin_all#one" = "Unpin {count} message"; "lng_pinned_unpin_all#other" = "Unpin all {count} messages"; "lng_pinned_unpin_all_sure" = "Do you want to unpin all messages?"; "lng_pinned_hide_all_sure" = "Do you want to hide the pinned message bar? It will stay hidden until a new message is pinned."; "lng_pinned_hide_all_hide" = "Hide"; "lng_binded" = "Dialog was binded."; "lng_unbinded" = "Dialog was unbinded."; "lng_edit_media_album_error" = "This file cannot be saved as a part of an album."; "lng_edit_media_invalid_file" = "Sorry, no way to use this file."; "lng_edit_photo_editor_hint" = "Left-click on the photo to edit."; "lng_edit_caption_attach" = "Sorry, you can't attach new media while editing a message."; "lng_edit_caption_voice" = "Sorry, you can't edit messages when you have an unsent voice message."; "lng_intro_about" = "Welcome to the official Telegram Desktop app.\nIt's fast and secure."; "lng_start_msgs" = "Start Messaging"; "lng_intro_next" = "Next"; "lng_intro_finish" = "Sign Up"; "lng_intro_submit" = "Submit"; "lng_photo_caption" = "Caption"; "lng_photos_comment" = "Comment"; "lng_intro_qr_title" = "Scan From Mobile Telegram"; "lng_intro_qr_step1" = "Open Telegram on your phone"; "lng_intro_qr_step2" = "Go to Settings > Devices > Link Desktop Device"; "lng_intro_qr_step3" = "Scan this image to Log In"; "lng_intro_qr_skip" = "Or log in using your phone number"; "lng_intro_qr_phone" = "Log in using phone number"; "lng_intro_qr_passkey" = "Log in using passkey"; "lng_intro_fragment_title" = "Enter code"; "lng_intro_fragment_about" = "Get the code for {phone_number} in the Anonymous Numbers section on Fragment."; "lng_intro_fragment_button" = "Open Fragment"; "lng_intro_email_setup_title" = "Choose a login email"; "lng_intro_email_confirm_subtitle" = "Please check your email {email} (don't forget the spam folder) and enter the code we just sent you."; "lng_phone_title" = "Your Phone Number"; "lng_phone_desc" = "Please confirm your country code\nand enter your phone number."; "lng_phone_to_qr" = "Quick log in using QR code"; "lng_country_code" = "Country Code"; "lng_bad_country_code" = "Invalid Country Code"; "lng_country_ph" = "Search"; "lng_country_none" = "Country not found"; "lng_country_select" = "Select Country"; "lng_phone_number" = "Phone number"; "lng_code_ph" = "Code"; "lng_code_desc" = "We've sent an activation code to your phone.\nPlease enter it below."; "lng_code_from_telegram" = "A code was sent **via Telegram** to your other\ndevices, if you have any connected."; "lng_code_no_telegram" = "Send code via SMS"; "lng_code_call" = "Telegram will call you in {minutes}:{seconds}"; "lng_code_calling" = "Requesting a call from Telegram..."; "lng_code_called" = "Telegram dialed your number"; "lng_bad_phone" = "Invalid phone number. Please try again."; "lng_bad_code" = "You have entered an invalid code."; "lng_bad_name" = "Enter your first and last name."; "lng_bad_photo" = "Sorry, Telegram can't process that type of image."; "lng_signin_title" = "Cloud password check"; "lng_signin_desc" = "Please enter your cloud password."; "lng_signin_recover_desc" = "Please enter the code from the email\n{email}"; "lng_signin_password" = "Your cloud password"; "lng_signin_code" = "Code from the email"; "lng_signin_recover" = "Forgot password?"; "lng_signin_recover_title" = "Password reset"; "lng_signin_hint" = "Hint: {password_hint}"; "lng_signin_recover_hint" = "We sent a code to {recover_email}"; "lng_signin_bad_password" = "You have entered a wrong password."; "lng_signin_wrong_code" = "You have entered an invalid code."; "lng_signin_try_password" = "Unable to access your email?"; "lng_signin_no_email_forgot" = "Since you didn't provide a recovery email when setting up your password, your remaining options are either to remember your password or to reset your account."; "lng_signin_cant_email_forgot" = "If you can't restore access to the email, your remaining options are either to remember your password or to reset your account."; "lng_signin_reset_account" = "Reset your account"; "lng_signin_sure_reset" = "You will lose all your Telegram chats, messages, media and files if you proceed.\n\nDo you want to reset your account?"; "lng_signin_reset" = "Reset"; "lng_signin_reset_wait" = "Since the account {phone_number} is active and protected by a password, it will be deleted in 1 week. This delay is required for security purposes. You can cancel this process anytime.\n\nYou'll be able to reset your account in:\n{when}"; "lng_signin_reset_in_days" = "{days_count} {hours_count} {minutes_count}"; "lng_signin_reset_in_hours" = "{hours_count} {minutes_count}"; "lng_signin_reset_cancelled" = "Your recent attempts to reset this account have been canceled by its active user. Please try again in 7 days."; "lng_signin_banned_text" = "This phone number is banned."; "lng_signin_banned_help" = "Help"; "lng_signup_title" = "Your Info"; "lng_signup_desc" = "Please enter your name and\nupload a photo."; "lng_signup_firstname" = "First name"; "lng_signup_lastname" = "Last name"; "lng_dlg_filter" = "Search"; "lng_dlg_new_group_name" = "Group name"; "lng_dlg_new_channel_name" = "Channel name"; "lng_dlg_new_bot_name" = "Bot name"; "lng_no_chats" = "Your chats will be here"; "lng_no_conversations" = "You have no\nconversations yet."; "lng_no_conversations_button" = "New Message"; "lng_no_conversations_subtitle" = "Your contacts on Telegram"; "lng_no_chats_filter" = "No chats currently belong to this folder."; "lng_no_saved_sublists" = "You can save messages from other chats here."; "lng_contacts_loading" = "Loading..."; "lng_contacts_not_found" = "No contacts found"; "lng_topics_not_found" = "No topics found."; "lng_forum_all_messages" = "All Messages"; "lng_forum_create_new_topic" = "Create New Thread"; "lng_dlg_search_for_messages" = "Search for messages"; "lng_update_telegram" = "Update Telegram"; "lng_dlg_search_in" = "Search messages in"; "lng_dlg_search_from" = "From: {user}"; "lng_chat_menu" = "Chat menu"; "lng_settings_save" = "Save"; "lng_settings_apply" = "Apply"; "lng_username_title" = "Username"; "lng_username_description1" = "You can choose a username on Telegram. If you do, other people will be able to find you by this username and contact you without knowing your phone number."; "lng_username_description2" = "You can use **a-z**, **0-9** and **underscores**.\nMinimum length is **5 characters**."; "lng_username_choose" = "Choose your username."; "lng_username_invalid" = "This username is invalid."; "lng_username_occupied" = "This username is already occupied."; "lng_username_too_short" = "This username is too short."; "lng_username_purchase_available" = "Sorry, this link is taken. But it's available for purchase. {link}"; "lng_username_purchase_available_link" = "Learn more..."; "lng_username_bad_symbols" = "Only a-z, 0-9, and underscores allowed."; "lng_username_available" = "This username is available."; "lng_username_not_found" = "Username @{user} not found."; "lng_username_by_phone_not_found" = "User {phone} not found."; "lng_username_app_not_found" = "Bot application not found."; "lng_username_link" = "This link opens a chat with you:"; "lng_username_copied" = "Link copied to clipboard."; "lng_username_text_copied" = "Username copied to clipboard."; "lng_usernames_edit" = "click to edit"; "lng_usernames_active" = "active"; "lng_usernames_non_active" = "inactive"; "lng_usernames_subtitle" = "Username order"; "lng_usernames_activate_error#one" = "Sorry, you can't activate more than **{count}** usernames."; "lng_usernames_activate_error#other" = "Sorry, you can't activate more than **{count}** usernames."; "lng_usernames_activate_description" = "Do you want to show this username on your info page?"; "lng_usernames_activate_confirm" = "Show"; "lng_channel_usernames_subtitle" = "Link order"; "lng_usernames_deactivate_description" = "Do you want to hide this username from your info page?"; "lng_usernames_deactivate_confirm" = "Hide"; "lng_usernames_description" = "Drag and drop links to change the order in which they will be displayed on your info page."; "lng_channel_usernames_activate_description" = "Do you want to show this link on the channel info page?"; "lng_channel_usernames_deactivate_description" = "Do you want to hide this link from the channel info page?"; "lng_channel_usernames_description" = "Drag and drop links to change the order in which they will be displayed on the channel info page."; "lng_bot_username_title" = "Username"; "lng_bot_username_description1" = "This link cannot be edited. You can acquire additional usernames on {link}."; "lng_bot_username_description1_link" = "Fragment"; "lng_bot_usernames_activate_description" = "Do you want to show this link on the bot info page?"; "lng_bot_usernames_deactivate_description" = "Do you want to hide this link from the bot info page?"; "lng_bot_usernames_description" = "Drag and drop links to change the order in which they will be displayed on the bot info page."; "lng_bio_placeholder" = "Bio"; "lng_collectible_username_title" = "{username} is a collectible username that belongs to"; "lng_collectible_username_info" = "This username was bought on **Fragment** on {date} for {price}"; "lng_collectible_username_copy" = "Copy Link"; "lng_collectible_phone_title" = "{phone} is a collectible phone number that belongs to"; "lng_collectible_phone_info" = "This phone number was bought on **Fragment** on {date} for {price}"; "lng_collectible_phone_copy" = "Copy Phone Number"; "lng_collectible_learn_more" = "Learn More"; "lng_collectible_phone_copied" = "Phone number copied to clipboard."; "lng_settings_section_info" = "Info"; // Fork settings. "lng_settings_section_fork" = "Fork Settings"; "lng_settings_square_avatats" = "Square avatars"; "lng_settings_audio_fade" = "Audio fade"; "lng_settings_uri_scheme" = "Open links with custom URI Scheme"; "lng_settings_uri_scheme_box_title" = "Custom URI Scheme"; "lng_settings_uri_scheme_field_label" = "Example: potplayer://."; "lng_settings_last_seen_in_dialogs" = "Show last seen time in list of dialogs"; "lng_settings_search_engine" = "Add a 'Search Selected Text' to Context Menu"; "lng_settings_search_engine_box_title" = "URL of Search Engine"; "lng_settings_search_engine_field_label" = "URL must contain '%q'"; "lng_settings_show_all_recent_stickers" = "Show all Recently used Stickers"; "lng_settings_use_black_tray_icon" = "Use black tray icon"; "lng_settings_use_original_tray_icon" = "Use original tray icon"; "lng_settings_auto_submit_passcode" = "Auto-submit local passcode"; "lng_settings_emoji_on_click" = "Disable emoji popup display on hovering"; "lng_settings_mention_by_name" = "Disable mention by name"; "lng_settings_primary_unmuted" = "Unmuted Messages are Primary"; "lng_settings_custom_sticker_size" = "Custom Sticker Size"; "lng_settings_sticker_size_label" = "Allowed values are between 50 and 256."; // Link Device (QR login). "lng_settings_link_device" = "Link Device"; "lng_settings_link_device_privacy" = "Your camera feed stays on your device. No video data is sent over the network — QR codes are scanned locally."; "lng_settings_link_device_start" = "Open Camera"; "lng_settings_link_device_scanning" = "Point camera at the QR code shown on the device you want to log in."; "lng_settings_link_device_success" = "Device linked successfully!"; "lng_settings_link_device_error" = "Could not link device: {error}"; "lng_settings_link_device_confirm" = "Do you want to link this device to your account?"; "lng_settings_link_device_stop" = "Stop Camera"; "lng_settings_link_device_clipboard" = "Scan QR from Clipboard"; "lng_context_open_uri_link" = "Open Link with URI Scheme"; "lng_context_search_selected" = "Search Selected Text"; "lng_info_id_label" = "ID"; "lng_profile_copy_id" = "Copy ID"; "lng_info_id_topic_label" = "Topic ID"; "lng_info_id_topic_value_label" = "{id}. Created at: {date}"; // "lng_settings_section_notify" = "Notifications and Sounds"; "lng_settings_show_from" = "Show notifications from"; "lng_settings_notify_all" = "All accounts"; "lng_settings_notify_all_about" = "Turn this off if you want to receive notifications only from the account you are currently using."; "lng_settings_notify_global" = "Global settings"; "lng_settings_notify_title" = "Notifications for chats"; "lng_settings_desktop_notify" = "Desktop notifications"; "lng_settings_master_volume_notifications" = "Volume"; "lng_settings_native_title" = "System integration"; "lng_settings_use_windows" = "Use Windows notifications"; "lng_settings_skip_in_focus" = "Respect system Focus mode"; "lng_settings_use_native_notifications" = "Use native notifications"; "lng_settings_notifications_position" = "Location on the screen"; "lng_settings_notifications_count" = "Notifications count"; "lng_settings_notifications_display" = "Display for notifications"; "lng_settings_notifications_display_default" = "Default"; "lng_settings_sound_allowed" = "Allow sound"; "lng_settings_alert_windows" = "Flash the taskbar icon"; "lng_settings_alert_mac" = "Bounce the Dock icon"; "lng_settings_alert_linux" = "Draw attention to the window"; "lng_settings_badge_title" = "Badge counter"; "lng_settings_include_muted" = "Include muted chats in unread count"; "lng_settings_include_muted_folders" = "Include muted chats in folder counters"; "lng_settings_count_unread" = "Count unread messages"; "lng_settings_events_title" = "Events"; "lng_settings_events_joined" = "Contact joined Telegram"; "lng_settings_events_pinned" = "Pinned messages"; "lng_settings_notifications_calls_title" = "Calls"; "lng_notification_preview_title" = "Dino Rex"; "lng_notification_preview_text" = "It's morning in Tokyo 😎"; "lng_notification_show_name" = "Name"; "lng_notification_show_text" = "Text"; "lng_notification_preview" = "You have a new message"; "lng_notification_reply" = "Reply"; "lng_notification_hide_all" = "Hide all"; "lng_notification_sample" = "This is a sample notification"; "lng_notification_reminder" = "Reminder"; "lng_notification_private_chats" = "Private chats"; "lng_notification_groups" = "Groups"; "lng_notification_channels" = "Channels"; "lng_notification_reactions" = "Reactions"; "lng_notification_reactions_title" = "Notifications for reactions"; "lng_notification_reactions_notify_about" = "Notify me about"; "lng_notification_reactions_messages" = "Messages"; "lng_notification_reactions_messages_full" = "Reactions to my messages"; "lng_notification_reactions_poll_votes" = "Poll votes"; "lng_notification_reactions_poll_votes_full" = "Votes in my polls"; "lng_notification_reactions_from" = "Notify about reactions from"; "lng_notification_reactions_from_nobody" = "Off"; "lng_notification_reactions_from_contacts" = "From my contacts"; "lng_notification_reactions_from_all" = "From everyone"; "lng_notification_reactions_settings" = "Settings"; "lng_notification_reactions_show_sender" = "Show sender's name"; "lng_notification_click_to_change" = "Click here to change"; "lng_notification_on" = "On, {exceptions}"; "lng_notification_off" = "Off, {exceptions}"; "lng_notification_exceptions#one" = "{count} exception"; "lng_notification_exceptions#other" = "{count} exceptions"; "lng_notification_exceptions_title" = "Exceptions"; "lng_notification_title_private_chats" = "Notifications for private chats"; "lng_notification_about_private_chats#one" = "Please note that **{count} chat** is listed as an exception and won't be affected by this change."; "lng_notification_about_private_chats#other" = "Please note that **{count} chats** are listed as exceptions and won't be affected by this change."; "lng_notification_volume_private_chats" = "Notifications volume for private chats"; "lng_notification_title_groups" = "Notifications for groups"; "lng_notification_about_groups#one" = "Please note that **{count} group** is listed as an exception and won't be affected by this change."; "lng_notification_about_groups#other" = "Please note that **{count} groups** are listed as exceptions and won't be affected by this change."; "lng_notification_volume_groups" = "Notifications volume for groups"; "lng_notification_title_channels" = "Notifications for channels"; "lng_notification_about_channels#one" = "Please note that **{count} channel** is listed as an exception and won't be affected by this change."; "lng_notification_about_channels#other" = "Please note that **{count} channels** are listed as exceptions and won't be affected by this change."; "lng_notification_volume_channel" = "Notifications volume for channels"; "lng_notification_exceptions_view" = "View exceptions"; "lng_notification_enable" = "Enable notifications"; "lng_notification_sound" = "Sound"; "lng_notification_tone" = "Notification tone"; "lng_notification_exceptions_muted" = "Muted"; "lng_notification_exceptions_unmuted" = "Unmuted"; "lng_notification_exceptions_add" = "Add an exception"; "lng_notification_exceptions_clear" = "Delete all exceptions"; "lng_notification_exceptions_clear_sure" = "Are you sure you want to delete all exceptions?"; "lng_notification_exceptions_clear_button" = "Delete"; "lng_notification_exceptions_remove" = "Remove"; "lng_notification_context_remove" = "Remove exception"; "lng_reaction_text" = "{reaction} to your \"{text}\""; "lng_reaction_notext" = "{reaction} to your message"; "lng_reaction_photo" = "{reaction} to your photo"; "lng_reaction_video" = "{reaction} to your video"; "lng_reaction_video_message" = "{reaction} to your video message"; "lng_reaction_document" = "{reaction} to your file"; "lng_reaction_sticker" = "{reaction} to your {emoji} sticker"; "lng_reaction_voice_message" = "{reaction} to your voice message"; "lng_reaction_contact" = "{reaction} to your contact {name}"; "lng_reaction_location" = "{reaction} to your map"; "lng_reaction_poll" = "{reaction} to your poll \"{title}\""; "lng_reaction_quiz" = "{reaction} to your quiz \"{title}\""; "lng_reaction_game" = "{reaction} to your game"; "lng_reaction_invoice" = "{reaction} to your invoice"; "lng_reaction_gif" = "{reaction} to your GIF"; "lng_poll_vote_option" = "voted for \"{option}\" in your poll"; "lng_poll_vote" = "voted in your poll \"{title}\""; "lng_poll_vote_notext" = "voted in your poll"; "lng_effect_add_title" = "Add an animated effect"; "lng_effect_stickers_title" = "Effects from stickers"; "lng_effect_send" = "Send with Effect"; "lng_effect_none" = "No effects found."; "lng_effect_premium" = "Subscribe to {link} to add this animated effect."; "lng_effect_premium_link" = "Telegram Premium"; "lng_languages" = "Language"; "lng_languages_none" = "No languages found."; "lng_languages_count#one" = "{count} language"; "lng_languages_count#other" = "{count} languages"; "lng_sure_save_language" = "Telegram will restart in order to change the language"; "lng_settings_update_automatically" = "Update automatically"; "lng_settings_install_beta" = "Install beta versions"; "lng_settings_current_version" = "Version {version}"; "lng_settings_check_now" = "Check for updates"; "lng_settings_update_checking" = "Checking for updates..."; "lng_settings_latest_installed" = "Latest version is installed"; "lng_settings_update_ready" = "New version is ready"; "lng_settings_update_fail" = "Update check failed :("; "lng_settings_workmode_tray" = "Show tray icon"; "lng_settings_workmode_window" = "Show taskbar icon"; "lng_settings_window_close" = "When window closed"; "lng_settings_run_in_background" = "Run in the background"; "lng_settings_quit_on_close" = "Quit the application"; "lng_settings_close_to_taskbar" = "Close to taskbar"; "lng_settings_monochrome_icon" = "Use monochrome icon"; "lng_settings_window_system" = "Window title bar"; "lng_settings_title_chat_name" = "Show chat name"; "lng_settings_title_account_name" = "Show active account"; "lng_settings_title_total_count" = "Total unread count"; "lng_settings_native_frame" = "Use system window frame"; "lng_settings_qt_frame" = "Use Qt window frame"; "lng_settings_auto_start" = "Launch Telegram when system starts"; "lng_settings_start_min" = "Launch minimized"; "lng_settings_auto_start_disabled_uwp" = "Starting with the system was disabled in Windows Settings.\n\nPlease enable Telegram Desktop in the Startup Apps Settings."; "lng_settings_open_system_settings" = "Open Settings"; "lng_settings_add_sendto" = "Place Telegram in \"Send to\" menu"; "lng_settings_mac_warn_before_quit" = "Show warning before quitting with {text}"; "lng_settings_mac_round_icon" = "Round application icon"; "lng_settings_experimental" = "Experimental settings"; "lng_settings_experimental_about" = "Warning! These are experimental settings. Some may not work. Others may break the app. Any of them may disappear in the next version without a trace. Use at your own risk."; "lng_settings_experimental_restore" = "Restore default values"; "lng_settings_experimental_irrelevant" = "This option isn't relevant for your system."; "lng_settings_section_chat_settings" = "Chat Settings"; "lng_settings_replace_emojis" = "Replace emoji automatically"; "lng_settings_system_text_replace" = "System text replacements"; "lng_settings_suggest_emoji" = "Suggest emoji replacements"; "lng_settings_suggest_animated_emoji" = "Suggest animated emoji"; "lng_settings_suggest_by_emoji" = "Suggest popular stickers by emoji"; "lng_settings_loop_stickers" = "Loop animated stickers"; "lng_settings_large_emoji" = "Large emoji"; "lng_settings_send_enter" = "Send with Enter"; "lng_settings_send_ctrlenter" = "Send with Ctrl+Enter"; "lng_settings_send_cmdenter" = "Send with Cmd+Enter"; "lng_settings_chat_quick_action_reply" = "Reply with double click"; "lng_settings_chat_quick_action_react" = "Send reaction with double click"; "lng_settings_chat_corner_reply" = "Reply button on messages"; "lng_settings_chat_corner_reaction" = "Reaction button on messages"; "lng_settings_shortcuts" = "Keyboard shortcuts"; "lng_shortcuts_reset" = "Reset to default"; "lng_shortcuts_recording" = "Recording..."; "lng_shortcuts_add_another" = "Add another"; "lng_shortcuts_close" = "Close the window"; "lng_shortcuts_lock" = "Lock the application"; "lng_shortcuts_minimize" = "Minimize the window"; "lng_shortcuts_quit" = "Quit the application"; "lng_shortcuts_media_play" = "Play the media"; "lng_shortcuts_media_pause" = "Pause the media"; "lng_shortcuts_media_play_pause" = "Toggle media playback"; "lng_shortcuts_media_stop" = "Stop media playback"; "lng_shortcuts_media_previous" = "Previous track"; "lng_shortcuts_media_next" = "Next track"; "lng_shortcuts_search" = "Search messages"; "lng_shortcuts_chat_previous" = "Previous chat"; "lng_shortcuts_chat_next" = "Next chat"; "lng_shortcuts_chat_first" = "First chat"; "lng_shortcuts_chat_last" = "Last chat"; "lng_shortcuts_chat_self" = "Saved Messages"; "lng_shortcuts_chat_pinned_n" = "Pinned chat #{index}"; "lng_shortcuts_show_account_n" = "Account #{index}"; "lng_shortcuts_show_all_chats" = "All Chats folder"; "lng_shortcuts_show_folder_n" = "Folder #{index}"; "lng_shortcuts_show_folder_last" = "Last folder"; "lng_shortcuts_folder_next" = "Next folder"; "lng_shortcuts_folder_previous" = "Previous folder"; "lng_shortcuts_scheduled" = "Scheduled messages"; "lng_shortcuts_archive" = "Archived chats"; "lng_shortcuts_contacts" = "Contacts list"; "lng_shortcuts_just_send" = "Just send"; "lng_shortcuts_silent_send" = "Silent send"; "lng_shortcuts_schedule" = "Schedule"; "lng_shortcuts_read_chat" = "Mark chat as read"; "lng_shortcuts_archive_chat" = "Archive chat"; "lng_shortcuts_media_fullscreen" = "Toggle video fullscreen"; "lng_shortcuts_show_chat_menu" = "Show chat menu"; "lng_shortcuts_show_chat_preview" = "Show chat preview"; "lng_shortcuts_record_voice_message" = "Record Voice Message"; "lng_shortcuts_record_round_message" = "Record Round Message"; "lng_shortcuts_admin_log" = "Group/Channel Recent Actions"; "lng_attach" = "Add attachment"; "lng_attach_replace" = "Replace attachment"; "lng_emoji_sticker_gif" = "Choose emoji, sticker or gif"; "lng_bot_keyboard_show" = "Show bot keyboard"; "lng_bot_keyboard_hide" = "Hide bot keyboard"; "lng_bot_commands_start" = "Bot commands start"; "lng_broadcast_silent" = "Silent broadcast"; "lng_settings_chat_reactions_title" = "Quick Reaction"; "lng_settings_chat_reactions_subtitle" = "Choose your favorite reaction"; "lng_settings_chat_message_reply_from" = "Bob Harris"; "lng_settings_chat_message_reply" = "Good morning"; "lng_settings_chat_message" = "Do you know what time it is?"; "lng_settings_section_filters" = "Folders"; "lng_settings_section_background" = "Chat wallpaper"; "lng_settings_bg_from_gallery" = "Choose from gallery"; "lng_settings_bg_from_file" = "Choose from file"; "lng_settings_bg_remove" = "Remove wallpaper"; "lng_settings_bg_theme_edit" = "Edit theme"; "lng_settings_bg_theme_create" = "Create new theme"; "lng_settings_bg_cloud_themes" = "Custom themes"; "lng_settings_bg_show_all" = "Show all themes"; "lng_settings_bg_tile" = "Tile background"; "lng_settings_adaptive_wide" = "Adaptive layout for wide screens"; "lng_settings_section_call_settings" = "Call Settings"; "lng_settings_call_camera" = "Camera"; "lng_settings_call_section_output" = "Speakers and headphones"; "lng_settings_call_section_input" = "Microphone"; "lng_settings_call_input_device" = "Input device"; "lng_settings_call_output_device" = "Output device"; "lng_settings_call_section_other" = "Other settings"; "lng_settings_call_open_system_prefs" = "Open system sound preferences"; "lng_settings_call_accept_calls" = "Accept calls on this device"; "lng_settings_call_device_default" = "Default"; "lng_settings_section_devices" = "Speakers and Camera"; "lng_settings_devices_calls" = "Calls and video chats"; "lng_settings_devices_calls_same" = "Use the same devices for calls"; "lng_settings_devices_inactive" = "Unavailable"; "lng_settings_language" = "Language"; "lng_settings_default_scale" = "Default interface scale"; "lng_settings_scale" = "Interface scale"; "lng_settings_connection_type" = "Connection type"; "lng_settings_downloading_update" = "Downloading update {progress}..."; "lng_settings_privacy_title" = "Privacy"; "lng_settings_last_seen" = "Last seen & online"; "lng_settings_calls" = "Calls"; "lng_settings_calls_peer_to_peer_title" = "Peer-to-peer"; "lng_settings_calls_peer_to_peer_button" = "Use peer-to-peer with"; "lng_settings_groups_invite" = "Groups & channels"; "lng_settings_phone_number_privacy" = "Phone number"; "lng_settings_forwards_privacy" = "Forwarded messages"; "lng_settings_profile_photo_privacy" = "Profile photos"; "lng_settings_messages_privacy" = "Messages"; "lng_settings_voices_privacy" = "Voice messages"; "lng_settings_bio_privacy" = "Bio"; "lng_settings_gifts_privacy" = "Gifts"; "lng_settings_birthday_privacy" = "Date of Birth"; "lng_settings_saved_music_privacy" = "Saved Music"; "lng_settings_privacy_premium" = "Only subscribers of {link} can restrict receiving voice messages."; "lng_settings_privacy_premium_link" = "Telegram Premium"; "lng_settings_passcode_disable" = "Disable passcode"; "lng_settings_passcode_disable_sure" = "Are you sure you want to disable passcode?"; "lng_settings_use_winhello" = "Unlock with Windows Hello"; "lng_settings_use_winhello_about" = "You need to enter your passcode once before unlocking Telegram with Windows Hello."; "lng_settings_use_touchid" = "Unlock with Touch ID"; "lng_settings_use_touchid_about" = "You need to enter your passcode once before unlocking Telegram with Touch ID."; "lng_settings_use_applewatch" = "Unlock with Apple Watch"; "lng_settings_use_applewatch_about" = "You need to enter your passcode once before unlocking Telegram with Apple Watch."; "lng_settings_use_systempwd" = "Unlock with System Password"; "lng_settings_use_systempwd_about" = "You need to enter your passcode once before unlocking Telegram with System Password."; "lng_settings_password_disable" = "Disable cloud password"; "lng_settings_password_abort" = "Abort two-step verification setup"; "lng_settings_about_bio" = "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco"; "lng_settings_name_label" = "Name"; "lng_settings_username_label" = "Username"; "lng_settings_phone_label" = "Phone number"; "lng_settings_username_add" = "Add username"; "lng_settings_username_about" = "Username lets people contact you on Telegram without needing your phone number."; "lng_settings_birthday_label" = "Date of Birth"; "lng_settings_birthday_title" = "Set your Birthday"; "lng_settings_birthday_add" = "Add"; "lng_settings_birthday_about" = "Choose who can see your birthday in {link}."; "lng_settings_birthday_about_link" = "Settings"; "lng_settings_birthday_contacts" = "Only your contacts can see your birthday. {link}"; "lng_settings_birthday_contacts_link" = "Change >"; "lng_settings_birthday_saved" = "Your date of birth was updated."; "lng_settings_birthday_suggested" = "Date of birth was suggested to {user}"; "lng_settings_birthday_reset" = "Remove"; "lng_settings_channel_label" = "Personal channel"; "lng_settings_channel_add" = "Add"; "lng_settings_channel_remove" = "Remove"; "lng_settings_channel_menu_remove" = "Remove Personal Channel"; "lng_settings_channel_no_yet" = "You don't have any public channels yet."; "lng_settings_channel_start" = "Start a Channel"; "lng_settings_channel_saved" = "Your personal channel was updated."; "lng_settings_channel_removed" = "Personal channel removed."; "lng_settings_add_account_about" = "You can add up to four accounts with different phone numbers."; "lng_settings_peer_to_peer_about" = "Disabling peer-to-peer will relay all calls through Telegram servers to avoid revealing your IP address, but may decrease audio and video quality."; "lng_settings_advanced" = "Advanced"; "lng_settings_stickers_emoji" = "Stickers and emoji"; "lng_settings_messages" = "Messages"; "lng_settings_themes" = "Themes"; "lng_settings_theme_day" = "Day"; "lng_settings_theme_classic" = "Classic"; "lng_settings_theme_tinted" = "Tinted"; "lng_settings_theme_night" = "Night"; "lng_settings_theme_accent_title" = "Choose accent color"; "lng_settings_theme_system_accent_color" = "System accent color"; "lng_settings_data_storage" = "Data and storage"; "lng_settings_information" = "Edit profile"; "lng_settings_my_account" = "My Account"; "lng_settings_security" = "Security"; "lng_settings_passcode_title" = "Local passcode"; "lng_settings_sessions_title" = "Active sessions"; "lng_settings_sessions_about" = "Manage your sessions on all your devices."; "lng_settings_archive_title" = "Archive Settings"; "lng_settings_new_unknown" = "New chats from unknown users"; "lng_settings_auto_archive" = "Archive and Mute"; "lng_settings_auto_archive_about" = "Automatically archive and mute new chats, groups and channels from non-contacts."; "lng_settings_unmuted_chats" = "Unmuted chats"; "lng_settings_always_in_archive" = "Always keep archived"; "lng_settings_unmuted_chats_about" = "Keep archived chats in the Archive even if they are unmuted and get a new message."; "lng_settings_chats_from_folders" = "Chats from folders"; "lng_settings_chats_from_folders_about" = "Keep archived chats from folders in the Archive even if they are unmuted and get a new message."; "lng_settings_destroy_title" = "Delete my account"; "lng_settings_version_info" = "Version and updates"; "lng_settings_system_integration" = "System integration"; "lng_settings_performance" = "Performance"; "lng_settings_enable_hwaccel" = "Hardware accelerated video decoding"; "lng_settings_enable_opengl" = "Enable OpenGL rendering for media"; "lng_settings_angle_backend" = "ANGLE graphics backend"; "lng_settings_angle_backend_auto" = "Auto"; "lng_settings_angle_backend_d3d9" = "Direct3D 9"; "lng_settings_angle_backend_d3d11" = "Direct3D 11"; "lng_settings_angle_backend_d3d11on12" = "D3D11on12"; "lng_settings_angle_backend_opengl" = "OpenGL"; "lng_settings_angle_backend_disabled" = "Disabled"; "lng_settings_top_peers_title" = "Frequent contacts"; "lng_settings_top_peers_suggest" = "Suggest frequent contacts"; "lng_settings_top_peers_about" = "Display people you message frequently at the top of the search section for quick access."; "lng_settings_sensitive_title" = "Sensitive content"; "lng_settings_sensitive_disable_filtering" = "Show 18+ Content"; "lng_settings_sensitive_about" = "Do not hide media that contains content suitable only for adults."; "lng_settings_security_bots" = "Bots and websites"; "lng_settings_file_confirmations" = "File open confirmations"; "lng_settings_edit_extensions" = "Extensions whitelist"; "lng_settings_edit_extensions_about" = "Open files with the following extensions without additional confirmation."; "lng_settings_edit_ip_confirm" = "IP reveal warning"; "lng_settings_edit_ip_confirm_about" = "Show confirmation when opening files that may reveal your IP address."; "lng_settings_clear_payment_info" = "Clear Payment and Shipping Info"; "lng_settings_logged_in" = "Connected websites"; "lng_settings_logged_in_title" = "Logged In with Telegram"; "lng_settings_logged_in_description" = "You can log in on websites that support signing in with Telegram."; "lng_settings_disconnect_all" = "Disconnect all websites"; "lng_settings_disconnect_title" = "Disconnect website"; "lng_settings_disconnect_sure" = "Are you sure you want to disconnect {domain}?"; "lng_settings_disconnect_block" = "Block {name}"; "lng_settings_disconnect_all_title" = "Disconnect websites"; "lng_settings_disconnect_all_sure" = "Are you sure you want to disconnect all websites where you logged in with Telegram?"; "lng_settings_disconnect" = "Disconnect"; "lng_settings_connected_title" = "Connected websites"; "lng_settings_suggestion_phone_number_title" = "Is {phone} still your number?"; "lng_settings_suggestion_phone_number_about" = "Keep your number up to date to ensure you can always log into Telegram. {link}"; "lng_settings_suggestion_phone_number_about_link" = "https://telegram.org/faq#q-i-have-a-new-phone-number-what-do-i-do"; "lng_settings_suggestion_phone_number_change" = "Please change your phone number in the official Telegram app on your phone as soon as possible. {emoji}"; "lng_settings_suggestion_password_title" = "Your password"; "lng_settings_suggestion_password_about" = "Your account is protected by 2-Step Veritifaction. Do you still remember your password?"; "lng_settings_suggestion_password_yes" = "Yes, definitely"; "lng_settings_suggestion_password_no" = "Not sure"; "lng_settings_suggestion_password_step_input_title" = "Enter your password"; "lng_settings_suggestion_password_step_input_about" = "Do you still remember your password?"; "lng_settings_suggestion_password_step_finish_title" = "Perfect!"; "lng_settings_suggestion_password_step_finish_about" = "You still remember your password."; "lng_settings_power_menu" = "Battery and Animations"; "lng_settings_power_title" = "Power Usage"; "lng_settings_power_subtitle" = "Power saving options"; "lng_settings_power_stickers" = "Animated Stickers"; "lng_settings_power_stickers_panel" = "Autoplay in panel"; "lng_settings_power_stickers_chat" = "Autoplay in chat"; "lng_settings_power_emoji" = "Animated Emoji"; "lng_settings_power_emoji_panel" = "Autoplay in panel"; "lng_settings_power_emoji_reactions" = "Autoplay in reactions menu"; "lng_settings_power_emoji_chat" = "Autoplay in messages"; "lng_settings_power_emoji_status" = "Autoplay in premium status"; "lng_settings_power_chat" = "Animations in Chats"; "lng_settings_power_chat_background" = "Wallpaper rotation"; "lng_settings_power_chat_spoiler" = "Animated spoiler effect"; "lng_settings_power_chat_effects" = "Effects in messages"; "lng_settings_power_calls" = "Animations in Calls"; "lng_settings_power_ui" = "Interface animations"; "lng_settings_power_auto" = "Save Power on Low Battery"; "lng_settings_power_auto_about" = "Automatically disable all animations when your laptop is in a battery saving mode."; "lng_settings_power_turn_off" = "Please turn off Save Power on Low Battery to change these settings."; "lng_settings_cloud_password_on" = "On"; "lng_settings_cloud_password_off" = "Off"; "lng_settings_cloud_password_start_title" = "Two-Step Verification"; "lng_settings_cloud_password_password_title" = "Password"; "lng_settings_cloud_password_hint_title" = "Password Hint"; "lng_settings_cloud_password_email_title" = "Recovery Email"; "lng_settings_cloud_password_start_about" = "Protect your Telegram account with an additional password."; "lng_settings_cloud_password_hint_about" = "You can create a hint for your password."; "lng_settings_cloud_password_email_about" = "Please enter your new recovery email. It is the only way to recover a forgotten password."; "lng_settings_cloud_password_password_subtitle" = "Create Password"; "lng_settings_cloud_password_check_subtitle" = "Your Password"; "lng_settings_cloud_password_hint_subtitle" = "Add Password Hint"; "lng_settings_cloud_password_email_subtitle" = "Add Recovery Email"; "lng_settings_cloud_password_email_recovery_subtitle" = "Password Recovery"; "lng_settings_cloud_password_manage_about1" = "You have Two-Step Verification enabled, so your account is protected with an additional password."; "lng_settings_cloud_password_manage_about2" = "This email is the only way to recover a forgotten password."; "lng_settings_cloud_password_manage_disable_sure" = "Are you sure you want to disable your password?"; "lng_settings_cloud_password_manage_email_new" = "Set Recovery Email"; "lng_settings_cloud_password_manage_email_change" = "Change Recovery Email"; "lng_settings_cloud_password_manage_password_change" = "Change Password"; "lng_settings_cloud_password_skip_hint" = "Skip setting hint"; "lng_settings_cloud_password_save" = "Save and Finish"; "lng_settings_cloud_password_email_confirm" = "Confirm and Finish"; "lng_settings_cloud_password_reset_in" = "You can reset your password in {duration}."; "lng_settings_cloud_login_email_section_title" = "Login Email"; "lng_settings_cloud_login_email_box_about" = "This email address will be used every time you log in to your Telegram account from a new device."; "lng_settings_cloud_login_email_box_ok" = "Change email"; "lng_settings_cloud_login_email_title" = "Enter New Email"; "lng_settings_cloud_login_email_placeholder" = "Enter Login Email"; "lng_settings_cloud_login_email_about" = "You will receive Telegram login codes via email and not SMS. Please enter an email address to which you have access."; "lng_settings_cloud_login_email_confirm" = "Confirm"; "lng_settings_cloud_login_email_code_title" = "Check Your New Email"; "lng_settings_cloud_login_email_code_about" = "Please enter the code we have sent to your new email {email}"; "lng_settings_cloud_login_email_success" = "Your email has been changed."; "lng_settings_cloud_login_email_set_success" = "Your login email has been set successfully."; "lng_settings_cloud_login_email_busy" = "Please set up login email in another window."; "lng_settings_error_email_not_alowed" = "Sorry, this email is not allowed"; "lng_settings_ttl_title" = "Auto-Delete Messages"; "lng_settings_ttl_about" = "Automatically delete messages for everyone after a period of time in all new chats you start."; "lng_settings_ttl_after" = "After {after_duration}"; "lng_settings_ttl_after_hours#one" = "{count} hour"; "lng_settings_ttl_after_hours#other" = "{count} hours"; "lng_settings_ttl_after_days#one" = "{count} day"; "lng_settings_ttl_after_days#other" = "{count} days"; "lng_settings_ttl_after_weeks#one" = "{count} week"; "lng_settings_ttl_after_weeks#other" = "{count} weeks"; "lng_settings_ttl_after_months#one" = "{count} month"; "lng_settings_ttl_after_months#other" = "{count} months"; "lng_settings_ttl_after_years#one" = "{count} year"; "lng_settings_ttl_after_years#other" = "{count} years"; "lng_settings_ttl_after_off" = "Off"; "lng_settings_ttl_after_custom" = "Set Custom Time"; "lng_settings_ttl_after_about" = "If enabled, all new messages in chats you start will be automatically deleted for everyone at some point after they are sent. You can also {link}."; "lng_settings_ttl_after_about_link" = "apply this setting for your existing chats"; "lng_settings_ttl_after_subtitle" = "Self-destruct timer"; "lng_settings_ttl_after_sure" = "Are you sure you want all messages in your new private chats and in new groups you create to be automatically deleted for everyone {after_duration} after they are sent?"; "lng_settings_ttl_after_toast" = "Messages in all new chats you start will be automatically deleted after {after_duration}."; "lng_settings_ttl_select_chats_sorry" = "Sorry, you can't set a self-destruct timer in this chat."; "lng_settings_ttl_select_chats_status" = "auto-delete after {after_duration}"; "lng_settings_ttl_select_chats_status_disabled" = "auto-delete disabled"; "lng_settings_ttl_select_chats_toast#one" = "Self-destruct timer for {duration} has been enabled in {count} selected chat."; "lng_settings_ttl_select_chats_toast#other" = "Self-destruct timer for {duration} has been enabled in {count} selected chats."; "lng_settings_ttl_select_chats_disabled_toast#one" = "Auto-delete timer has been disabled in {count} selected chat."; "lng_settings_ttl_select_chats_disabled_toast#other" = "Auto-delete timer has been disabled in {count} selected chats."; "lng_clear_payment_info_title" = "Clear payment info"; "lng_clear_payment_info_sure" = "Are you sure you want to clear your payment and shipping info?"; "lng_clear_payment_info_shipping" = "Shipping info"; "lng_clear_payment_info_payment" = "Payment info"; "lng_clear_payment_info_clear" = "Clear"; "lng_clear_payment_info_confirm" = "Delete your shipping info and instruct all payment providers to remove your saved credit cards? Note that Telegram never stores your credit card data."; "lng_settings_theme_settings" = "Theme settings"; "lng_settings_theme_name_color" = "Your name color"; "lng_settings_auto_night_mode" = "Auto-night mode"; "lng_settings_auto_night_mode_off" = "Off"; "lng_settings_auto_night_mode_on" = "System"; "lng_settings_auto_night_warning" = "You have enabled auto-night mode. If you want to change the dark mode settings, you'll need to disable it first."; "lng_settings_auto_night_disable" = "Disable"; "lng_settings_font_family" = "Font family"; "lng_settings_color_title" = "Color preview"; "lng_settings_color_tab_profile" = "Profile"; "lng_settings_color_tab_name" = "Name"; "lng_settings_color_reply" = "Reply to your message"; "lng_settings_color_reply_channel" = "Reply to your channel message"; "lng_settings_color_text" = "Your name and replies to your messages will be shown in the selected color."; "lng_settings_color_text_channel" = "The name of the channel and replies to its messages will be shown in the selected color."; "lng_settings_color_link_name" = "Telegram"; "lng_settings_color_link_title" = "Link Preview"; "lng_settings_color_link_description" = "Previews of links you send will also use this color."; "lng_settings_color_about" = "This color will be used for your name, the links you send, and replies to your messages."; "lng_settings_color_about_channel" = "This color will be used for your channel's name, the links it sends, and replies to its posts."; "lng_settings_color_emoji" = "Add icons to replies"; "lng_settings_color_emoji_remove" = "Remove icon"; "lng_settings_color_emoji_off" = "Off"; "lng_settings_color_emoji_about" = "Make replies to your messages stand out by adding custom patterns to them."; "lng_settings_color_emoji_about_channel" = "Select an icon to create a custom pattern for replies to your messages."; "lng_settings_color_changed" = "Your name color has been updated!"; "lng_settings_color_changed_channel" = "Your channel color has been updated!"; "lng_settings_color_changed_profile" = "Your profile style has been updated!"; "lng_settings_color_changed_profile_channel" = "Your channel profile style has been updated!"; "lng_settings_color_apply" = "Apply Style"; "lng_settings_color_wear" = "Wear Collectible"; "lng_settings_color_profile_emoji" = "Add icons to Profile"; "lng_settings_color_profile_emoji_channel" = "Profile Logo"; "lng_settings_color_reset" = "Reset Profile Color"; "lng_settings_color_profile_about" = "You can change the color of your name and customize replies to you. {link}"; "lng_settings_color_profile_about_link" = "Change {emoji}"; "lng_settings_color_choose_channel" = "Choose a color and a logo for your channel's profile"; "lng_settings_color_choose_group" = "Choose a color and a logo for the group's profile"; "lng_settings_color_group_boost_footer#one" = "The group has **{count}** boost. {link}"; "lng_settings_color_group_boost_footer#other" = "The group has **{count}** boosts. {link}"; "lng_settings_color_group_boost_footer_link" = "What are boosts?"; "lng_suggest_hide_new_title" = "Hide new chats?"; "lng_suggest_hide_new_about" = "You are receiving lots of new chats from users who are not in your Contact List.\n\nDo you want to have such chats **automatically muted** and **archived**?"; "lng_suggest_hide_new_to_settings" = "Go to Settings"; "lng_settings_spellchecker" = "Spell checker"; "lng_settings_system_spellchecker" = "Use system spell checker"; "lng_settings_custom_spellchecker" = "Use spell checker"; "lng_settings_auto_download_dictionaries" = "Download dictionaries automatically"; "lng_settings_manage_dictionaries" = "Manage dictionaries"; "lng_settings_manage_enabled_dictionary" = "Dictionary is enabled"; "lng_settings_manage_remove_dictionary" = "Remove Dictionary"; "lng_settings_gift_premium" = "Premium Gifting"; "lng_settings_gift_premium_users_confirm" = "Proceed"; "lng_settings_gift_premium_users_error#one" = "You can select maximum {count} user."; "lng_settings_gift_premium_users_error#other" = "You can select maximum {count} users."; "lng_settings_gift_premium_choose" = "Please choose at least one recipient."; "lng_backgrounds_header" = "Choose a Wallpaper"; "lng_theme_sure_keep" = "Keep this theme?"; "lng_theme_reverting#one" = "Reverting to the old theme in {count} second."; "lng_theme_reverting#other" = "Reverting to the old theme in {count} seconds."; "lng_theme_keep_changes" = "Keep changes"; "lng_theme_revert" = "Revert"; "lng_theme_no_desktop" = "Sorry, this theme doesn't include a version for Telegram Desktop."; "lng_theme_share" = "Share"; "lng_theme_edit" = "Edit"; "lng_theme_delete" = "Delete"; "lng_theme_delete_sure" = "Are you sure you want to delete this theme?"; "lng_background_header" = "Wallpaper preview"; "lng_background_text1" = "Ah, you kids today with techno music! You should enjoy the classics, like Hasselhoff!"; "lng_background_text2" = "I can't even take you seriously right now."; "lng_background_bad_link" = "Invalid wallpaper link."; "lng_background_share" = "Share"; "lng_background_link_copied" = "Link copied to clipboard."; "lng_background_blur" = "Blurred"; "lng_background_sure_delete" = "Are you sure you want to delete this wallpaper?"; "lng_background_other_info" = "{user} will be able to apply this wallpaper"; "lng_background_other_channel" = "All subscribers will see this wallpaper"; "lng_background_other_group" = "All members will see this wallpaper"; "lng_background_apply1" = "Apply the wallpaper in this chat."; "lng_background_apply2" = "Looks good."; "lng_background_apply_button" = "Apply For This Chat"; "lng_background_dimming" = "Wallpaper dimming"; "lng_background_sure_reset_default" = "Are you sure you want to reset the wallpaper?"; "lng_background_reset_default" = "Reset"; "lng_background_apply_me" = "Apply for me"; "lng_background_apply_both" = "Apply for me and {user}"; "lng_background_apply_channel" = "Apply For Channel"; "lng_background_apply_group" = "Apply For Group"; "lng_download_path_ask" = "Ask download path for each file"; "lng_download_path" = "Download path"; "lng_download_path_temp" = "Temp folder"; "lng_download_path_default" = "Default folder"; "lng_download_path_header" = "Choose download path"; "lng_download_path_default_radio" = "Telegram folder in system «Downloads»"; "lng_download_path_temp_radio" = "Temp folder, cleared on logout or uninstall"; "lng_download_path_dir_radio" = "Custom folder, cleared only manually"; "lng_download_path_choose" = "Choose download path"; "lng_download_path_failed" = "File download could not be started.\n\nThis might be because your selected download location is invalid. Try changing it in Settings > Advanced > Download Path."; "lng_download_finish_failed" = "File download could not be completed.\n\nWould you like to try again?"; "lng_settings_section_privacy" = "Privacy and Security"; "lng_local_storage_title" = "Local storage"; "lng_local_storage_empty" = "No cached files"; "lng_local_storage_image#one" = "{count} image"; "lng_local_storage_image#other" = "{count} images"; "lng_local_storage_sticker#one" = "{count} sticker"; "lng_local_storage_sticker#other" = "{count} stickers"; "lng_local_storage_voice#one" = "{count} voice message"; "lng_local_storage_voice#other" = "{count} voice messages"; "lng_local_storage_round#one" = "{count} video message"; "lng_local_storage_round#other" = "{count} video messages"; "lng_local_storage_animation#one" = "{count} GIF animation"; "lng_local_storage_animation#other" = "{count} GIF animations"; "lng_local_storage_media" = "Media cache"; "lng_local_storage_size_limit" = "Total size limit: {size}"; "lng_local_storage_media_limit" = "Media cache limit: {size}"; "lng_local_storage_time_limit" = "Clear files older than: {limit}"; "lng_local_storage_limit_never" = "Never"; "lng_local_storage_summary" = "Summary"; "lng_local_storage_clear_some" = "Clear"; "lng_local_storage_clear" = "Clear all"; "lng_local_storage_clearing" = "Clearing..."; "lng_passcode_remove_button" = "Remove"; "lng_passcode_change" = "Change passcode"; "lng_passcode_create" = "Local passcode"; "lng_passcode_remove" = "Remove local passcode"; "lng_passcode_autolock" = "Auto-Lock"; "lng_passcode_autolock_away" = "Auto-Lock if away for..."; "lng_passcode_autolock_inactive" = "Auto-Lock if inactive for..."; "lng_passcode_autolock_hours_minutes" = "{hours_count}h {minutes_count}m"; "lng_passcode_enter_old" = "Enter current passcode"; "lng_passcode_enter_first" = "Enter a passcode"; "lng_passcode_enter_new" = "Enter new passcode"; "lng_passcode_confirm_new" = "Re-enter new passcode"; "lng_passcode_about" = "When a local passcode is set, a lock icon appears at the top of your chat list. Click it to lock Telegram Desktop.\n\nNote: if you forget your local passcode, you'll need to log out of Telegram Desktop and log in again."; "lng_passcode_about1" = "When a local passcode is set, a lock icon appears at the top of your chat list."; "lng_passcode_about2" = "Click it to lock Telegram Desktop."; "lng_passcode_about3" = "Note: if you forget your passcode, you'll need to log out of Telegram Desktop and log in again."; "lng_passcode_differ" = "Passcodes are different"; "lng_passcode_wrong" = "Wrong passcode"; "lng_passcode_is_same" = "Passcode was not changed"; "lng_passcode_enter" = "Enter your local passcode"; "lng_passcode_ph" = "Your passcode"; "lng_passcode_submit" = "Submit"; "lng_passcode_logout" = "Log out"; "lng_passcode_winhello" = "You need to enter your passcode\nbefore you can use Windows Hello."; "lng_passcode_touchid" = "You need to enter your passcode\nbefore you can use Touch ID."; "lng_passcode_applewatch" = "You need to enter your passcode\nbefore you can use Watch to unlock."; "lng_passcode_systempwd" = "You need to enter your passcode\nbefore you can use system password."; "lng_passcode_winhello_unlock" = "Telegram wants to unlock with Windows Hello."; "lng_passcode_touchid_unlock" = "unlock"; "lng_passcode_create_button" = "Save Passcode"; "lng_passcode_check_button" = "Submit"; "lng_passcode_change_button" = "Save Passcode"; "lng_passcode_create_title" = "Create Local Passcode"; "lng_passcode_check_title" = "Enter Passcode"; "lng_passcode_change_title" = "Enter Passcode"; "lng_cloud_password_waiting_code" = "Confirmation code sent to {email}..."; "lng_cloud_password_confirm" = "Confirm recovery email"; "lng_cloud_password_change" = "Change cloud password"; "lng_cloud_password_create" = "Telegram password"; "lng_cloud_password_remove" = "Remove cloud password"; "lng_cloud_password_reset_ready" = "Reset password"; "lng_cloud_password_enter_old" = "Enter current password"; "lng_cloud_password_enter_first" = "Enter a password"; "lng_cloud_password_enter_new" = "Enter new password"; "lng_cloud_password_confirm_new" = "Re-enter new password"; "lng_cloud_password_hint" = "Add a password hint"; "lng_cloud_password_change_hint" = "Enter new password hint"; "lng_cloud_password_bad" = "Password and hint cannot be the same."; "lng_cloud_password_email" = "Enter recovery email"; "lng_cloud_password_bad_email" = "Invalid email"; "lng_cloud_password_about" = "This password will be asked when you log in on a new device in addition to the code you get via SMS."; "lng_cloud_password_about_recover" = "Warning! Are you sure you don't want to\nadd a password recovery email?\n\nIf you forget your password, you will\nlose access to your Telegram account."; "lng_cloud_password_skip_email" = "Skip email"; "lng_cloud_password_was_set" = "Two-step verification enabled."; "lng_cloud_password_updated" = "Your cloud password was updated."; "lng_cloud_password_removed" = "Two-step verification was disabled."; "lng_cloud_password_differ" = "Passwords do not match"; "lng_cloud_password_wrong" = "Wrong cloud password"; "lng_cloud_password_is_same" = "Password was not changed"; "lng_cloud_password_passport_losing" = "Warning! All data saved in your Telegram Passport will be lost."; "lng_cloud_password_resend" = "Resend code"; "lng_cloud_password_resent" = "Code was resent."; "lng_cloud_password_reset_no_email" = "Since you didn't provide a recovery email when setting up your password, your remaining options are either to remember your password or wait 7 days until your password is reset."; "lng_cloud_password_reset_with_email" = "If you don't have access to your recovery email, your remaining options are either to remember your password or wait 7 days until your password resets."; "lng_cloud_password_reset_ok" = "Reset"; "lng_cloud_password_reset_cancel_title" = "Cancel reset"; "lng_cloud_password_reset_cancel_sure" = "Cancel the password reset process? If you request a new reset later, it will take another 7 days."; "lng_cloud_password_reset_later" = "You recently requested a password reset that was canceled. Please wait {duration} before making a new request."; "lng_cloud_password_expired" = "Please re-enter your password."; "lng_connection_auto_connecting" = "Default (connecting...)"; "lng_connection_auto" = "Default ({transport} used)"; "lng_connection_proxy_connecting" = "Connecting through proxy..."; "lng_connection_proxy" = "{transport} with proxy"; "lng_connection_try_ipv6" = "Try connecting through IPv6"; "lng_connection_host_ph" = "Hostname"; "lng_connection_port_ph" = "Port"; "lng_connection_user_ph" = "Username"; "lng_connection_password_ph" = "Password"; "lng_connection_proxy_secret_ph" = "Secret"; "lng_connection_save" = "Save"; "lng_proxy_settings" = "Proxy settings"; "lng_proxy_disable" = "Disable proxy"; "lng_proxy_use_system_settings" = "Use system proxy settings"; "lng_proxy_use_custom" = "Use custom proxy"; "lng_proxy_use_for_calls" = "Use proxy for calls"; "lng_proxy_about" = "Proxy servers may be helpful in accessing Telegram if there is no connection in a specific region."; "lng_proxy_add" = "Add proxy"; "lng_proxy_share" = "Share"; "lng_proxy_online" = "online"; "lng_proxy_checking" = "checking…"; "lng_proxy_connecting" = "connecting…"; "lng_proxy_available" = "available (ping: {ping} ms)"; "lng_proxy_unavailable" = "not available"; "lng_proxy_edit" = "Edit proxy"; "lng_proxy_menu_edit" = "Edit"; "lng_proxy_menu_delete" = "Delete"; "lng_proxy_menu_restore" = "Restore"; "lng_proxy_edit_share" = "Share"; "lng_proxy_edit_share_qr_box_title" = "Share proxy with QR code"; "lng_proxy_edit_share_list_button" = "Share Proxy List"; "lng_proxy_edit_share_list_toast" = "Proxy List copied to clipboard."; "lng_proxy_address_label" = "Socket address"; "lng_proxy_credentials_optional" = "Credentials (optional)"; "lng_proxy_credentials" = "Credentials"; "lng_proxy_description" = "Your saved proxy list will be here."; "lng_proxy_sponsor" = "Proxy sponsor"; "lng_proxy_sponsor_about" = "This channel is shown by your proxy server.\nTo remove this channel from your chat list,\ndisable the proxy in Telegram Settings."; "lng_proxy_sponsor_warning" = "This proxy may display a sponsored channel in your chat list. This doesn't reveal any of your Telegram traffic."; "lng_proxy_add_from_clipboard" = "Add proxy from clipboard"; "lng_proxy_add_from_clipboard_good_toast" = "Proxy was added from clipboard."; "lng_proxy_add_from_clipboard_failed_toast" = "This is not a proxy link."; "lng_proxy_add_from_clipboard_existing_toast" = "This proxy is already in the list."; "lng_badge_psa_default" = "PSA"; "lng_about_psa_default" = "This message provides you with a public service announcement. To remove it from your chat list, right click it and select **Hide**."; "lng_tooltip_psa_default" = "This message provides you with a public service announcement."; "lng_settings_blocked_users" = "Blocked users"; "lng_settings_no_blocked_users" = "None"; "lng_settings_show_sessions" = "Active sessions"; "lng_settings_export_data" = "Export Telegram data"; "lng_settings_destroy_if" = "If away for..."; "lng_settings_terminate_title" = "Terminate old sessions"; "lng_settings_terminate_if" = "If inactive for..."; "lng_settings_reset_sure" = "Are you sure you want to terminate\nall other sessions?"; "lng_settings_reset_one_sure" = "Do you want to terminate this session?"; "lng_settings_reset_button" = "Terminate"; "lng_settings_rename_device" = "Rename"; "lng_settings_device_name" = "Device name"; "lng_settings_rename_device_title" = "Rename current device"; "lng_settings_manage_local_storage" = "Manage local storage"; "lng_settings_ask_question" = "Ask a Question"; "lng_settings_ask_sure" = "Please note that Telegram Support is done by volunteers. We try to respond as quickly as possible, but it may take a while.\n\nPlease take a look at the Telegram FAQ: it has important troubleshooting tips and answers to most questions."; "lng_settings_faq_button" = "Go to FAQ"; "lng_settings_ask_ok" = "Ask a Volunteer"; "lng_settings_faq" = "Telegram FAQ"; "lng_settings_faq_subtitle" = "FAQ"; "lng_settings_faq_link" = "https://telegram.org/faq#general-questions"; "lng_settings_features" = "Telegram Features"; "lng_settings_credits" = "My Stars"; "lng_settings_currency" = "My TON"; "lng_settings_logout" = "Log out"; "lng_sure_logout" = "Are you sure you want to log out?"; "lng_settings_need_restart" = "You need to restart for applying some of the new settings. Restart now?"; "lng_settings_restart_now" = "Restart"; "lng_settings_restart_later" = "Later"; "lng_settings_passkeys_title" = "Passkeys"; "lng_settings_passkeys_about" = "Manage your passkey, stored safely in the cloud service you choose."; "lng_settings_passkeys_button" = "Add Passkey"; "lng_settings_passkeys_button_about" = "Your passkey is stored securely in your password manager. {link}"; "lng_settings_passkeys_delete_sure_title" = "Delete Passkey"; "lng_settings_passkeys_delete_sure_about" = "Once deleted, this passkey can't be used to log in."; "lng_settings_passkeys_delete_sure_about2" = "Don't forget to remove it from your password manager too."; "lng_settings_passkeys_none_title" = "Protect your account"; "lng_settings_passkeys_none_about" = "Log in safely and keep your account secure."; "lng_settings_passkeys_none_info1_title" = "Create a Passkey"; "lng_settings_passkeys_none_info1_about" = "Make a passkey to sign in easily and safely."; "lng_settings_passkeys_none_info2_title" = "Log in with face recognition"; "lng_settings_passkeys_none_info2_about" = "Use your face, fingerprint, or screen lock to sign in."; "lng_settings_passkeys_none_info3_title" = "Store Passkey securely"; "lng_settings_passkeys_none_info3_about" = "Your passkey is stored safely in the cloud service you choose."; "lng_settings_passkeys_none_button" = "Create Passkey"; "lng_settings_passkeys_none_button_unsupported" = "Unsupported"; "lng_settings_passkeys_created" = "Created {date}"; "lng_settings_passkeys_last_used" = "Last used {date}"; "lng_settings_passkeys_unsigned_error" = "Passkeys are not available in unsigned builds. Please use an official signed version of Telegram Desktop."; "lng_settings_passkey_unknown" = "Passkey"; "lng_settings_quick_dialog_action_title" = "Chat list quick action"; "lng_settings_quick_dialog_action_about" = "Choose the action you want to perform when you middle-click or swipe left in the chat list."; "lng_settings_quick_dialog_action_both" = "Swipe left and Middle-click"; "lng_settings_quick_dialog_action_swipe" = "Swipe left"; "lng_settings_quick_dialog_action_mute" = "Mute"; "lng_settings_quick_dialog_action_unmute" = "Unmute"; "lng_settings_quick_dialog_action_pin" = "Pin"; "lng_settings_quick_dialog_action_unpin" = "Unpin"; "lng_settings_quick_dialog_action_read" = "Read"; "lng_settings_quick_dialog_action_unread" = "Unread"; "lng_settings_quick_dialog_action_archive" = "Archive"; "lng_settings_quick_dialog_action_unarchive" = "Unarchive"; "lng_settings_quick_dialog_action_delete" = "Delete"; "lng_settings_quick_dialog_action_disabled" = "Change folder"; "lng_quick_dialog_action_toast_mute_success" = "Notifications for this chat have been muted."; "lng_quick_dialog_action_toast_unmute_success" = "Notifications enabled for this chat."; "lng_quick_dialog_action_toast_pin_success" = "The chat has been pinned."; "lng_quick_dialog_action_toast_unpin_success" = "The chat has been unpinned."; "lng_quick_dialog_action_toast_read_success" = "The chat has been marked as read."; "lng_quick_dialog_action_toast_unread_success" = "The chat has been marked as unread."; "lng_quick_dialog_action_toast_archive_success" = "The chat has been archived."; "lng_quick_dialog_action_toast_unarchive_success" = "The chat has been unarchived."; "lng_archive_hint_title" = "This is your Archive"; "lng_archive_hint_about" = "Archived chats will remain in the Archive when you receive a new message. {link}"; "lng_archive_hint_about_unmuted" = "When you receive a new message, muted chats will remain in the Archive, while unmuted chats will be moved to Chats. {link}"; "lng_archive_hint_about_link" = "Tap to change {emoji}"; "lng_archive_hint_section_1" = "Archived Chats"; "lng_archive_hint_section_1_info" = "Move any chat into your Archive and back by swiping on it."; "lng_archive_hint_section_2" = "Hiding Archive"; "lng_archive_hint_section_2_info" = "Hide the Archive from your Main screen by swiping on it."; "lng_archive_hint_section_3" = "Stories"; "lng_archive_hint_section_3_info" = "Archive Stories from your contacts separately from chats with them."; "lng_archive_hint_button" = "Got it"; "lng_settings_generic_subscribe" = "Subscribe to {link} to use this setting."; "lng_settings_generic_subscribe_link" = "Telegram Premium"; "lng_sessions_header" = "This device"; "lng_sessions_other_header" = "Active Devices"; "lng_sessions_other_desc" = "You can log in to Telegram from other mobile, tablet and desktop devices, using the same phone number. All your data will be instantly synchronized."; "lng_sessions_terminate_all" = "Terminate all other sessions"; "lng_sessions_terminate_all_about" = "Logs out all devices except for this one."; "lng_sessions_incomplete" = "Incomplete login attempts"; "lng_sessions_incomplete_about" = "The devices above have no access to your messages. The code was entered correctly, but no correct password was given."; "lng_sessions_info" = "Info"; "lng_sessions_terminate" = "Terminate Session"; "lng_sessions_application" = "Application"; "lng_sessions_system" = "System version"; "lng_sessions_browser" = "Browser"; "lng_sessions_ip" = "IP address"; "lng_sessions_location" = "Location"; "lng_sessions_location_about" = "This location estimate is based on the IP address and may not always be accurate."; "lng_sessions_about_apps" = "The official Telegram app is available for Android, iPhone, iPad, Windows, macOS and Linux."; "lng_blocked_list_title" = "Blocked users"; "lng_blocked_list_unknown_phone" = "unknown phone number"; "lng_blocked_list_unblock" = "Unblock"; "lng_blocked_list_add" = "Block user"; "lng_blocked_list_add_title" = "Select user to block"; "lng_blocked_list_already_blocked" = "already blocked"; "lng_blocked_list_about" = "Blocked users can't send you messages or add you to groups. They will not see your profile photos, stories, online and last seen status."; "lng_blocked_list_not_found" = "No users found."; "lng_blocked_list_confirm_title" = "Block {name}"; "lng_blocked_list_confirm_text" = "Do you want to block {name} from messaging and calling you on Telegram?"; "lng_blocked_list_confirm_clear" = "Delete this chat"; "lng_blocked_list_confirm_ok" = "Block"; "lng_blocked_list_empty_title" = "No blocked users"; "lng_blocked_list_empty_description" = "You haven't blocked anyone yet."; "lng_blocked_list_subtitle#one" = "{count} blocked user"; "lng_blocked_list_subtitle#other" = "{count} blocked users"; "lng_edit_privacy_everyone" = "Everybody"; "lng_edit_privacy_no_miniapps" = "Not Mini Apps"; "lng_edit_privacy_contacts" = "My contacts"; "lng_edit_privacy_close_friends" = "Close friends"; "lng_edit_privacy_contacts_and_premium" = "Contacts & Premium"; "lng_edit_privacy_paid" = "Paid"; "lng_edit_privacy_contacts_and_miniapps" = "Contacts & Mini Apps"; "lng_edit_privacy_nobody" = "Nobody"; "lng_edit_privacy_premium" = "Premium users"; "lng_edit_privacy_miniapps" = "Mini Apps"; "lng_edit_privacy_exceptions" = "Add exceptions"; "lng_edit_privacy_user_types" = "User types"; "lng_edit_privacy_users_and_groups" = "Users and groups"; "lng_edit_privacy_premium_status" = "all Telegram Premium subscribers"; "lng_edit_privacy_miniapps_status" = "web mini apps that you use"; "lng_edit_privacy_exceptions_count#one" = "{count} user"; "lng_edit_privacy_exceptions_count#other" = "{count} users"; "lng_edit_privacy_exceptions_premium_and" = "Premium & {users}"; "lng_edit_privacy_exceptions_miniapps_and" = "Mini Apps & {users}"; "lng_edit_privacy_exceptions_add" = "Add users"; "lng_edit_privacy_phone_number_title" = "Phone number privacy"; "lng_edit_privacy_phone_number_header" = "Who can see my phone number"; "lng_edit_privacy_phone_number_warning" = "Users who have your number saved in their contacts will also see it on Telegram."; "lng_edit_privacy_phone_number_always_empty" = "Always share with"; "lng_edit_privacy_phone_number_never_empty" = "Never share with"; "lng_edit_privacy_phone_number_exceptions" = "Add users or groups to override the settings above."; "lng_edit_privacy_phone_number_always_title" = "Always share with"; "lng_edit_privacy_phone_number_never_title" = "Never share with"; "lng_edit_privacy_phone_number_find" = "Who can find me by my number"; "lng_edit_privacy_phone_number_contacts" = "Users who add your number to their contacts will see it on Telegram only if they are your contacts."; "lng_edit_privacy_lastseen_title" = "Last Seen & Online"; "lng_edit_privacy_lastseen_header" = "Who can see my last seen time"; "lng_edit_privacy_lastseen_warning" = "Unless you are a Premium user, you won't see Last Seen or Online statuses for people with whom you don't share yours. Approximate times will be shown instead (recently, within a week, within a month)."; "lng_edit_privacy_lastseen_always_empty" = "Always share with"; "lng_edit_privacy_lastseen_never_empty" = "Never share with"; "lng_edit_privacy_lastseen_exceptions" = "You can add users or entire groups as exceptions that will override the settings above."; "lng_edit_privacy_lastseen_always_title" = "Always share with"; "lng_edit_privacy_lastseen_never_title" = "Never share with"; "lng_edit_lastseen_hide_read_time" = "Hide read time"; "lng_edit_lastseen_hide_read_time_about" = "Hide the time when you read messages from people who can't see your last seen. If you turn this on, their read time will also be hidden from you (unless you are a Premium user).\n\nThis setting does not affect group chats."; "lng_edit_lastseen_subscribe" = "Subscribe to Telegram Premium"; "lng_edit_lastseen_subscribe_about" = "If you subscribe to Premium, you will see other users' last seen and read time even if you hid yours from them (unless they specifically restricted it)."; "lng_edit_privacy_groups_title" = "Groups & Channels"; "lng_edit_privacy_groups_header" = "Who can add me to groups and channels"; "lng_edit_privacy_groups_always_empty" = "Always allow"; "lng_edit_privacy_groups_never_empty" = "Never allow"; "lng_edit_privacy_groups_exceptions" = "These users will or will not be able to add you to groups and channels regardless of the settings above."; "lng_edit_privacy_groups_always_title" = "Always allow"; "lng_edit_privacy_groups_never_title" = "Never allow"; "lng_edit_privacy_about_title" = "Bio"; "lng_edit_privacy_about_header" = "Who can see my bio"; "lng_edit_privacy_about_always_empty" = "Always share with"; "lng_edit_privacy_about_never_empty" = "Never share with"; "lng_edit_privacy_about_exceptions" = "These users will or will not be able to see your profile bio regardless of the settings above."; "lng_edit_privacy_about_always_title" = "Always Share With"; "lng_edit_privacy_about_never_title" = "Never Share With"; "lng_edit_privacy_birthday_title" = "Date of birth privacy"; "lng_edit_privacy_birthday_header" = "Who can see my date of birth"; "lng_edit_privacy_birthday_always_empty" = "Always allow"; "lng_edit_privacy_birthday_never_empty" = "Never allow"; "lng_edit_privacy_birthday_exceptions" = "These users will or will not be able to see your date of birth regardless of the settings above."; "lng_edit_privacy_birthday_always_title" = "Always allow"; "lng_edit_privacy_birthday_never_title" = "Never allow"; "lng_edit_privacy_birthday_yet" = "You haven't entered your date of birth yet.\n{link}"; "lng_edit_privacy_birthday_yet_link" = "Add my birthday >"; "lng_edit_privacy_gifts_title" = "Gifts"; "lng_edit_privacy_gifts_header" = "Who can display gifts on my profile"; "lng_edit_privacy_gifts_always_empty" = "Always allow"; "lng_edit_privacy_gifts_never_empty" = "Never allow"; "lng_edit_privacy_gifts_exceptions" = "Choose whether gifts from specific senders need your approval before they're visible to others on your profile."; "lng_edit_privacy_gifts_always_title" = "Always allow"; "lng_edit_privacy_gifts_never_title" = "Never allow"; "lng_edit_privacy_gifts_types" = "Accepted Gift Types"; "lng_edit_privacy_gifts_premium" = "Premium Subscriptions"; "lng_edit_privacy_gifts_unlimited" = "Unlimited"; "lng_edit_privacy_gifts_limited" = "Limited-Edition"; "lng_edit_privacy_gifts_unique" = "Unique"; "lng_edit_privacy_gifts_channels" = "From Channels"; "lng_edit_privacy_gifts_types_about" = "Choose the types of gifts that you accept."; "lng_edit_privacy_gifts_show_icon" = "Show Gift Icon in Chats"; "lng_edit_privacy_gifts_show_icon_about" = "Display the {emoji}Gift icon in the message input field for both participants in all chats."; "lng_edit_privacy_gifts_restricted" = "This user doesn't accept gifts."; "lng_edit_privacy_calls_title" = "Calls"; "lng_edit_privacy_calls_header" = "Who can call me"; "lng_edit_privacy_calls_always_empty" = "Always allow"; "lng_edit_privacy_calls_never_empty" = "Never allow"; "lng_edit_privacy_calls_exceptions" = "These users will or will not be able to call you regardless of the settings above."; "lng_edit_privacy_calls_always_title" = "Always allow"; "lng_edit_privacy_calls_never_title" = "Never allow"; "lng_edit_privacy_calls_p2p_title" = "Peer-to-peer in calls"; "lng_edit_privacy_calls_p2p_header" = "Use peer-to-peer with"; "lng_edit_privacy_calls_p2p_always_empty" = "Always allow"; "lng_edit_privacy_calls_p2p_never_empty" = "Never allow"; "lng_edit_privacy_calls_p2p_exceptions" = "Peer-to-peer in calls will or will not be used with these users regardless of the settings above."; "lng_edit_privacy_calls_p2p_always_title" = "Always allow"; "lng_edit_privacy_calls_p2p_never_title" = "Never allow"; "lng_edit_privacy_calls_p2p_everyone" = "Everybody"; "lng_edit_privacy_calls_p2p_contacts" = "My contacts"; "lng_edit_privacy_calls_p2p_nobody" = "Nobody"; "lng_edit_privacy_forwards_title" = "Forwarded Messages"; "lng_edit_privacy_forwards_header" = "Who can add a link to my account when forwarding my messages"; "lng_edit_privacy_forwards_warning" = "Messages you send will not link back to your account when forwarded by other users."; "lng_edit_privacy_forwards_always_empty" = "Always allow"; "lng_edit_privacy_forwards_never_empty" = "Never allow"; "lng_edit_privacy_forwards_exceptions" = "These settings will override the values above."; "lng_edit_privacy_forwards_exceptions_everyone" = "You can add users or entire groups that will not see your profile photo."; "lng_edit_privacy_forwards_exceptions_nobody" = "Add users or entire groups which will still see your profile photo."; "lng_edit_privacy_forwards_always_title" = "Always Allow"; "lng_edit_privacy_forwards_never_title" = "Never Allow"; "lng_edit_privacy_forwards_sample_message" = "Reinhardt, we need to find you some new tunes 🎶"; "lng_edit_privacy_forwards_sample_everyone" = "Link to your account."; "lng_edit_privacy_forwards_sample_contacts" = "Link if allowed by settings below."; "lng_edit_privacy_forwards_sample_nobody" = "Not a link to your account."; "lng_edit_privacy_profile_photo_title" = "Profile Photos"; "lng_edit_privacy_profile_photo_header" = "Who can see my profile photos"; "lng_edit_privacy_profile_photo_always_empty" = "Always share with"; "lng_edit_privacy_profile_photo_never_empty" = "Never share with"; "lng_edit_privacy_profile_photo_always_title" = "Always Share With"; "lng_edit_privacy_profile_photo_never_title" = "Never Share With"; "lng_edit_privacy_profile_photo_public_set" = "Set Public Photo"; "lng_edit_privacy_profile_photo_public_update" = "Update Public Photo"; "lng_edit_privacy_profile_photo_public_remove" = "Remove Public Photo"; "lng_edit_privacy_profile_photo_public_about" = "You can upload a public photo for users who are restricted from viewing your real profile photos."; "lng_edit_privacy_voices_title" = "Voice Messages"; "lng_edit_privacy_voices_header" = "Who can send me voice messages"; "lng_edit_privacy_voices_always_empty" = "Always allow"; "lng_edit_privacy_voices_never_empty" = "Never allow"; "lng_edit_privacy_voices_exceptions" = "These users will or will not be able to send voice and video messages to you regardless of the settings above."; "lng_edit_privacy_voices_always_title" = "Always allow"; "lng_edit_privacy_voices_never_title" = "Never Allow"; "lng_edit_privacy_saved_music_title" = "Saved Music"; "lng_edit_privacy_saved_music_header" = "Who can see my saved music in profile"; "lng_edit_privacy_saved_music_always_empty" = "Always allow"; "lng_edit_privacy_saved_music_never_empty" = "Never allow"; "lng_edit_privacy_saved_music_exceptions" = "These users will or will not be able to see your saved music regardless of the settings above."; "lng_edit_privacy_saved_music_always_title" = "Always allow"; "lng_edit_privacy_saved_music_never_title" = "Never allow"; "lng_messages_privacy_title" = "Messages"; "lng_messages_privacy_subtitle" = "Who can send me messages"; "lng_messages_privacy_everyone" = "Everybody"; "lng_messages_privacy_restricted" = "My Contacts and Premium Users"; "lng_messages_privacy_about" = "You can restrict messages from users who are not in your contacts and don't have Premium."; "lng_messages_privacy_premium_button" = "Subscribe to Telegram Premium"; "lng_messages_privacy_premium_about" = "Subscribe now to change this setting and get access to other exclusive features of Telegram Premium."; "lng_messages_privacy_premium" = "Only subscribers of {link} can select this option."; "lng_messages_privacy_premium_link" = "Telegram Premium"; "lng_messages_privacy_charge" = "Charge for messages"; "lng_messages_privacy_charge_about" = "Charge a fee for messages from people outside your contacts or those you haven't messaged first."; "lng_messages_privacy_price" = "Set your price per message"; "lng_messages_privacy_price_about" = "You will receive {percent} of the selected fee ({amount}) for each incoming message."; "lng_messages_privacy_exceptions" = "Exceptions"; "lng_messages_privacy_remove_fee" = "Remove Fee"; "lng_messages_privacy_remove_about" = "Add users or entire groups who won't be charged for sending messages to you."; "lng_self_destruct_title" = "Account self-destruction"; "lng_self_destruct_description" = "If you don't come online at least once within this period, your account will be deleted along with all groups, messages and contacts."; "lng_self_destruct_sessions_title" = "Session termination"; "lng_self_destruct_sessions_description" = "If you don't come online from a specific session at least once within this period, it will be terminated."; "lng_change_phone_new_submit" = "Submit"; "lng_change_phone_code_title" = "Enter code"; "lng_change_phone_error" = "You can only change your phone number using mobile Telegram apps. Please use an official Telegram app on your phone to update your number."; "lng_mute_menu_mute" = "Mute"; "lng_mute_menu_unmute" = "Unmute"; "lng_mute_menu_duration_any" = "Mute for {duration}"; "lng_mute_menu_duration" = "Mute for..."; "lng_mute_menu_duration_forever" = "Mute forever"; "lng_mute_menu_duration_unmute" = "Unmute"; "lng_mute_menu_sound_on" = "Enable sound"; "lng_mute_menu_sound_off" = "Disable sound"; "lng_mute_menu_sound_select" = "Select tone"; "lng_mute_box_title" = "Mute notifications for..."; "lng_preview_loading" = "Getting Link Info..."; "lng_preview_cant" = "Could not generate preview for this link."; "lng_profile_settings_section" = "Settings"; "lng_profile_bot_settings" = "Bot Settings"; "lng_profile_bot_help" = "Bot Help"; "lng_profile_bot_privacy" = "Bot Privacy Policy"; "lng_profile_bot_privacy_url" = "https://telegram.org/privacy-tpa"; "lng_profile_common_groups#one" = "{count} group in common"; "lng_profile_common_groups#other" = "{count} groups in common"; "lng_profile_similar_channels#one" = "{count} similar channel"; "lng_profile_similar_channels#other" = "{count} similar channels"; "lng_profile_similar_bots#one" = "{count} similar bot"; "lng_profile_similar_bots#other" = "{count} similar bots"; "lng_profile_saved_messages#one" = "{count} saved message"; "lng_profile_saved_messages#other" = "{count} saved messages"; "lng_profile_peer_gifts#one" = "{count} gift"; "lng_profile_peer_gifts#other" = "{count} gifts"; "lng_profile_unofficial_warning" = "{icon} {name} uses an unofficial Telegram client — messages to this user may be less secure."; "lng_profile_participants_section" = "Members"; "lng_profile_subscribers_section" = "Subscribers"; "lng_profile_add_contact" = "Add Contact"; "lng_profile_clear_and_exit" = "Delete and leave"; "lng_profile_leave_channel" = "Leave channel"; "lng_profile_delete_channel" = "Delete channel"; "lng_profile_leave_group" = "Leave group"; "lng_profile_delete_group" = "Delete group"; "lng_profile_report" = "Report"; "lng_profile_block_bot" = "Stop and block bot"; "lng_profile_restart_bot" = "Restart bot"; "lng_profile_invite_to_group" = "Add to Group"; "lng_profile_add_bot_as_admin" = "Add to Group or Channel"; "lng_profile_invite_to_channel" = "Add to Channel"; "lng_profile_invite_to_group_about" = "This bot is able to manage a group."; "lng_profile_invite_to_channel_about" = "This bot is able to manage a channel."; "lng_profile_add_bot_as_admin_about" = "This bot is able to manage a group or channel."; "lng_profile_add_participant" = "Add Members"; "lng_profile_add_via_link" = "Invite via Link"; "lng_profile_hide_participants" = "Hide Members"; "lng_profile_hide_participants_about" = "Switch this on to hide the list of members in this group. Admins will remain visible."; "lng_profile_view_channel" = "View Channel"; "lng_profile_view_discussion" = "View discussion"; "lng_profile_direct_messages" = "Direct messages"; "lng_profile_join_channel" = "Join Channel"; "lng_profile_join_group" = "Join Group"; "lng_profile_apply_to_join_group" = "Apply to Join Group"; "lng_profile_kick" = "Remove"; "lng_profile_delete_removed" = "Delete"; "lng_profile_sure_kick" = "Remove {user} from the group?"; "lng_profile_sure_kick_channel" = "Remove {user} from the channel?"; "lng_profile_sure_remove_admin" = "Remove {user} from admins?"; "lng_profile_loading" = "Loading..."; "lng_profile_saved_stories#one" = "{count} post"; "lng_profile_saved_stories#other" = "{count} posts"; "lng_profile_posts#one" = "{count} post"; "lng_profile_posts#other" = "{count} posts"; "lng_profile_photos#one" = "{count} photo"; "lng_profile_photos#other" = "{count} photos"; "lng_profile_gifs#one" = "{count} GIF"; "lng_profile_gifs#other" = "{count} GIFs"; "lng_profile_polls#one" = "{count} poll"; "lng_profile_polls#other" = "{count} polls"; "lng_profile_videos#one" = "{count} video"; "lng_profile_videos#other" = "{count} videos"; "lng_profile_songs#one" = "{count} audio file"; "lng_profile_songs#other" = "{count} audio files"; "lng_profile_files#one" = "{count} file"; "lng_profile_files#other" = "{count} files"; "lng_profile_audios#one" = "{count} voice message"; "lng_profile_audios#other" = "{count} voice messages"; "lng_profile_shared_links#one" = "{count} shared link"; "lng_profile_shared_links#other" = "{count} shared links"; "lng_profile_copy_phone" = "Copy Phone Number"; "lng_profile_copy_fullname" = "Copy Name"; "lng_profile_photo_by_you" = "photo set by you"; "lng_profile_public_photo" = "public photo"; "lng_profile_administrators#one" = "{count} administrator"; "lng_profile_administrators#other" = "{count} administrators"; "lng_profile_manage" = "Channel settings"; "lng_profile_topic_toast" = "This topic contains {name}"; "lng_invite_upgrade_title" = "Upgrade to Premium"; "lng_invite_upgrade_group_invite#one" = "{users} only accepts invitations to groups from Contacts and **Premium** users."; "lng_invite_upgrade_group_invite#other" = "{users} only accept invitations to groups from Contacts and **Premium** users."; "lng_invite_upgrade_group_write#one" = "{users} only accepts messages and invitations to groups from Contacts and **Premium** users."; "lng_invite_upgrade_group_write#other" = "{users} only accept messages and invitations to groups from Contacts and **Premium** users."; "lng_invite_upgrade_channel_invite#one" = "{users} only accepts invitations to channels from Contacts and **Premium** users."; "lng_invite_upgrade_channel_invite#other" = "{users} only accept invitations to channels from Contacts and **Premium** users."; "lng_invite_upgrade_channel_write#one" = "{users} only accepts messages and invitations to channels from Contacts and **Premium** users."; "lng_invite_upgrade_channel_write#other" = "{users} only accept messages and invitations to channels from Contacts and **Premium** users."; "lng_invite_upgrade_users_few" = "{users} and {last}"; "lng_invite_upgrade_users_many#one" = "{users} and **{count}** more person"; "lng_invite_upgrade_users_many#other" = "{users} and **{count}** more people"; "lng_invite_upgrade_or" = "or"; "lng_invite_upgrade_via_title" = "Invite via Link"; "lng_invite_upgrade_via_group_about" = "You can send an invite link to the group in a private message instead."; "lng_invite_upgrade_via_channel_about" = "You can send an invite link to the channel in a private message instead."; "lng_invite_status_disabled" = "available only to Premium users"; "lng_leave_next_owner_box_title" = "Leave Channel?"; "lng_leave_next_owner_box_title_group" = "Leave Group?"; "lng_leave_next_owner_box_about" = "If you leave, **{user}** will become the new owner of **{chat}** in **1 week**."; "lng_leave_next_owner_box_about_admin" = "If you leave, **{user}** will become the new admin of **{chat}** in **1 week**."; "lng_leave_next_owner_box_about_legacy" = "If you leave, **{user}** will immediately become the new owner of **{chat}**."; "lng_leave_next_owner_box_about_admin_legacy" = "If you leave, **{user}** will immediately become the new admin of **{chat}**."; "lng_select_next_owner_box" = "Appoint Another Owner"; "lng_select_next_owner_box_admin" = "Appoint Another Admin"; "lng_select_next_owner_box_title" = "Appoint New Owner"; "lng_select_next_owner_box_title_admin" = "Appoint New Admin"; "lng_select_next_owner_box_confirm" = "Appoint and Leave Group"; "lng_select_next_owner_box_sub_admins" = "Channel admins"; "lng_select_next_owner_box_sub_admins_group" = "Group admins"; "lng_select_next_owner_box_sub_members" = "Channel members"; "lng_select_next_owner_box_sub_members_group" = "Group members"; "lng_select_next_owner_box_status_joined" = "joined {date}"; "lng_select_next_owner_box_status_promoted" = "promoted {date}"; "lng_select_next_owner_box_empty_list" = "There are no eligible participants to appoint as owner."; "lng_select_next_owner_box_empty_list_admin" = "There are no eligible participants to appoint as admin."; "lng_via_link_group_one" = "**{user}** restricts adding them to groups.\nYou can send them an invite link as message instead."; "lng_via_link_group_many#one" = "**{count} user** restricts adding them to groups.\nYou can send them an invite link as message instead."; "lng_via_link_group_many#other" = "**{count} users** restrict adding them to groups.\nYou can send them an invite link as message instead."; "lng_via_link_channel_one" = "**{user}** restricts adding them to channels.\nYou can send them an invite link as message instead."; "lng_via_link_channel_many#one" = "**{count} user** restricts adding them to channels.\nYou can send them an invite link as message instead."; "lng_via_link_channel_many#other" = "**{count} users** restrict adding them to channels.\nYou can send them an invite link as message instead."; "lng_via_link_send" = "Send Invite Link"; "lng_via_link_cant" = "You can't create a link"; "lng_via_link_cant_one" = "**{user}** can only be invited via link, but you don't have permission to share invite links to this group."; "lng_via_link_cant_many#one" = "**{count} user** can only be invited via link, but you don't have permission to share invite links to this group."; "lng_via_link_cant_many#other" = "**{count} users** can only be invited via link, but you don't have permission to share invite links to this group."; "lng_via_link_shared_one" = "Link shared with **{user}**."; "lng_via_link_shared_many#one" = "Link shared with **{count} user**."; "lng_via_link_shared_many#other" = "Link shared with **{count} users**."; "lng_info_personal_channel_label" = "Channel"; "lng_info_mobile_label" = "Mobile"; "lng_info_mobile_context_menu_fragment_about" = "This number is not tied to a SIM card and was acquired on {link}."; "lng_info_mobile_context_menu_fragment_about_link" = "Fragment"; "lng_info_mobile_hidden" = "Hidden"; "lng_info_username_label" = "Username"; "lng_info_usernames_label" = "also"; "lng_info_birthday_label" = "Date of birth"; "lng_info_birthday_years#one" = "{date} ({count} year old)"; "lng_info_birthday_years#other" = "{date} ({count} years old)"; "lng_info_birthday_today_years#one" = "{date}\n({count} year old)"; "lng_info_birthday_today_years#other" = "{date}\n({count} years old)"; "lng_info_birthday_today_label" = "Birthday today"; "lng_info_birthday_today" = "{emoji} {date}"; "lng_info_notes_label" = "Notes"; "lng_info_notes_private" = "only visible to you"; "lng_edit_note" = "Edit Note"; "lng_delete_note" = "Delete Note"; "lng_info_bio_label" = "Bio"; "lng_info_link_label" = "Link"; "lng_info_link_topic_label" = "This topic link will only work for group members"; "lng_info_location_label" = "Location"; "lng_info_about_label" = "Description"; "lng_info_work_open" = "Open"; "lng_info_work_closed" = "Closed"; "lng_info_hours_label" = "Business hours"; "lng_info_hours_closed" = "closed"; "lng_info_hours_opens_in_minutes#one" = "opens in {count} minute"; "lng_info_hours_opens_in_minutes#other" = "opens in {count} minutes"; "lng_info_hours_opens_in_hours#one" = "opens in {count} hour"; "lng_info_hours_opens_in_hours#other" = "opens in {count} hours"; "lng_info_hours_opens_in_days#one" = "opens in {count} day"; "lng_info_hours_opens_in_days#other" = "opens in {count} days"; "lng_info_hours_open_full" = "open 24 hours"; "lng_info_hours_next_day" = "{time} (next day)"; "lng_info_hours_local_time" = "local time"; "lng_info_hours_my_time" = "my time"; "lng_info_user_title" = "User Info"; "lng_info_bot_title" = "Bot Info"; "lng_info_group_title" = "Group Info"; "lng_info_channel_title" = "Channel Info"; "lng_info_topic_title" = "Topic Info"; "lng_info_thread_title" = "Thread Info"; "lng_profile_enable_notifications" = "Notifications"; "lng_profile_send_message" = "Send Message"; "lng_profile_open_app" = "Open App"; "lng_profile_open_app_short" = "Open"; "lng_profile_open_app_about" = "By launching this mini app, you agree to the {terms}."; "lng_profile_open_app_terms" = "Terms of Service for Mini Apps"; "lng_profile_open_photo" = "Open Photo"; "lng_profile_bot_permissions_title" = "Allow access to"; "lng_profile_bot_emoji_status_access" = "Emoji Status"; "lng_info_add_as_contact" = "Add to contacts"; "lng_profile_shared_media" = "Shared media"; "lng_profile_suggest_photo" = "Suggest Profile Photo"; "lng_profile_suggest_photo_from_clipboard" = "Suggest From Clipboard"; "lng_profile_set_photo_for" = "Set Profile Photo"; "lng_profile_set_photo_for_group" = "Set Group Photo"; "lng_profile_set_photo_for_channel" = "Set Channel Photo"; "lng_profile_set_photo_for_from_clipboard" = "Set From Clipboard"; "lng_profile_set_photo_for_about" = "You can replace {user}'s photo with another photo that only you will see."; "lng_profile_photo_reset" = "Reset to Original"; "lng_profile_photo_reset_button" = "Reset"; "lng_profile_photo_reset_sure" = "Are you sure you want to reset {user}'s photo to the original?"; "lng_profile_photo_from_clipboard" = "From clipboard"; "lng_profile_suggest_sure" = "You can suggest {user} to set this photo for their Telegram profile."; "lng_profile_suggest_button" = "Suggest"; "lng_profile_set_personal_sure" = "Only you will see this photo and it will replace any photo {user} sets for themselves."; "lng_profile_accept_photo_sure" = "{user} suggests this photo for your Telegram profile."; "lng_profile_set_photo_button" = "Set Photo"; "lng_profile_accept_video_sure" = "{user} suggests this photo for your Telegram profile."; "lng_profile_set_video_button" = "Set Photo"; "lng_profile_changed_photo_title" = "Photo updated"; "lng_profile_changed_photo_about" = "You can change it in {link}."; "lng_profile_changed_photo_link" = "Settings"; "lng_profile_action_short_message" = "Message"; "lng_profile_action_short_channel" = "Channel"; "lng_profile_action_short_mute" = "Mute"; "lng_profile_action_short_unmute" = "Unmute"; "lng_profile_action_short_call" = "Call"; "lng_profile_action_short_discuss" = "Discuss"; "lng_profile_action_short_gift" = "Gift"; "lng_profile_action_short_join" = "Join"; "lng_profile_action_short_report" = "Report"; "lng_profile_action_short_leave" = "Leave"; "lng_profile_action_short_more" = "More"; "lng_profile_action_short_manage" = "Manage"; "lng_media_type_photos" = "Photos"; "lng_media_type_gifs" = "GIFs"; "lng_media_type_videos" = "Videos"; "lng_media_type_songs" = "Audio files"; "lng_media_type_files" = "Files"; "lng_media_type_audios" = "Voice messages"; "lng_media_type_links" = "Shared links"; "lng_media_type_polls" = "Polls"; "lng_polls_search_none" = "No polls found"; "lng_media_type_rounds" = "Video messages"; "lng_media_saved_music_your" = "Your playlist"; "lng_media_saved_music_title" = "Playlist"; "lng_profile_common_groups_section" = "Groups in common"; "lng_info_edit_contact" = "Edit contact"; "lng_info_delete_contact" = "Delete contact"; "lng_info_share_contact" = "Share this contact"; "lng_profile_clear_history" = "Clear history"; "lng_profile_delete_conversation" = "Delete chat"; "lng_profile_block_user" = "Block user"; "lng_profile_unblock_user" = "Unblock user"; "lng_profile_export_chat" = "Export chat history"; "lng_profile_export_topic" = "Export topic history"; "lng_profile_gift_premium" = "Gift Premium"; "lng_media_selected_photo#one" = "{count} Photo"; "lng_media_selected_photo#other" = "{count} Photos"; "lng_media_selected_gif#one" = "{count} GIF"; "lng_media_selected_gif#other" = "{count} GIFs"; "lng_media_selected_video#one" = "{count} Video"; "lng_media_selected_video#other" = "{count} Videos"; "lng_media_selected_song#one" = "{count} Audio file"; "lng_media_selected_song#other" = "{count} Audio files"; "lng_media_selected_file#one" = "{count} File"; "lng_media_selected_file#other" = "{count} Files"; "lng_media_selected_audio#one" = "{count} Voice message"; "lng_media_selected_audio#other" = "{count} Voice messages"; "lng_media_selected_link#one" = "{count} shared link"; "lng_media_selected_link#other" = "{count} shared links"; "lng_media_selected_poll#one" = "{count} Poll"; "lng_media_selected_poll#other" = "{count} Polls"; "lng_media_photo_empty" = "No photos here yet"; "lng_media_gif_empty" = "No GIFs here yet"; "lng_media_video_empty" = "No videos here yet"; "lng_media_song_empty" = "No music files here yet"; "lng_media_file_empty" = "No files here yet"; "lng_media_audio_empty" = "No voice messages here yet"; "lng_media_link_empty" = "No shared links here yet"; "lng_media_song_empty_search" = "No music files found"; "lng_media_file_empty_search" = "No files found"; "lng_media_link_empty_search" = "No shared links found"; "lng_manage_group_title" = "Manage group"; "lng_manage_channel_title" = "Manage Channel"; "lng_manage_bot_title" = "Manage Bot"; "lng_manage_peer_recent_actions" = "Recent actions"; "lng_manage_peer_star_ref" = "Affiliate programs"; "lng_manage_peer_members" = "Members"; "lng_manage_peer_subscribers" = "Subscribers"; "lng_manage_peer_administrators" = "Administrators"; "lng_manage_peer_exceptions" = "Exceptions"; "lng_manage_peer_removed_users" = "Removed users"; "lng_manage_peer_permissions" = "Permissions"; "lng_manage_peer_invite_links" = "Invite links"; "lng_manage_peer_reactions" = "Reactions"; "lng_manage_peer_reactions_on" = "All"; "lng_manage_peer_reactions_off" = "Off"; "lng_manage_peer_requests" = "Join Requests"; "lng_manage_peer_requests_channel" = "Join Requests"; "lng_manage_peer_reactions_enable" = "Enable Reactions"; "lng_manage_peer_reactions_about_channel" = "Allow subscribers to react to channel posts."; "lng_manage_peer_reactions_all" = "All reactions"; "lng_manage_peer_reactions_all_about" = "Members of the group can use any emoji as reactions to messages."; "lng_manage_peer_reactions_some" = "Some reactions"; "lng_manage_peer_reactions_some_about" = "Members of the group can use only certain approved emoji as reactions to messages."; "lng_manage_peer_reactions_none" = "No reactions"; "lng_manage_peer_reactions_none_about" = "Members of the group can't add any reactions to messages."; "lng_manage_peer_reactions_some_title" = "Only allow these reactions"; "lng_manage_peer_reactions_available" = "Available reactions"; "lng_manage_peer_reactions_available_ph" = "Add reactions..."; "lng_manage_peer_reactions_own" = "You can also {link} emoji packs and use them as reactions."; "lng_manage_peer_reactions_own_link" = "create your own"; "lng_manage_peer_reactions_level#one" = "Your channel needs to reach level **{count}** to use **{same_count}** custom reaction."; "lng_manage_peer_reactions_level#other" = "Your channel needs to reach level **{count}** to use **{same_count}** custom reactions."; "lng_manage_peer_reactions_boost" = "Boost your channel {link}."; "lng_manage_peer_reactions_boost_link" = "here"; "lng_manage_peer_reactions_limit" = "Channels can't have more custom reactions."; "lng_manage_peer_reactions_max_title" = "Maximum number of reactions"; "lng_manage_peer_reactions_max_slider#one" = "{count} reaction per post"; "lng_manage_peer_reactions_max_slider#other" = "{count} reactions per post"; "lng_manage_peer_reactions_max_about" = "Limit the number of different reactions that can be added to a post, including already published ones."; "lng_manage_peer_reactions_paid" = "Enable Paid Reactions"; "lng_manage_peer_reactions_paid_about" = "Switch this on to let your subscribers react to posts with Telegram Stars, which you will be able to withdraw as TON. {link}"; "lng_manage_peer_reactions_paid_link" = "Learn more >"; "lng_manage_peer_antispam" = "Aggressive Anti-Spam"; "lng_manage_peer_antispam_about" = "Telegram will filter more spam but may occasionally affect ordinary messages. You can report False Positives in Recent Actions."; "lng_manage_peer_antispam_not_enough#one" = "Aggressive filtering can be enabled only in groups with more than **{count} member**."; "lng_manage_peer_antispam_not_enough#other" = "Aggressive filtering can be enabled only in groups with more than **{count} members**."; "lng_manage_peer_group_type" = "Group type"; "lng_manage_peer_channel_type" = "Channel type"; "lng_manage_peer_link_type" = "Link type"; "lng_manage_peer_link_permanent" = "Permanent link"; "lng_manage_peer_link_invite" = "Invite link"; "lng_manage_peer_link_expired" = "Expired link"; "lng_manage_private_group_title" = "Private"; "lng_manage_private_group_noforwards_title" = "Private restricted"; "lng_manage_public_group_title" = "Public"; "lng_manage_private_peer_title" = "Private"; "lng_manage_private_peer_noforwards_title" = "Private restricted"; "lng_manage_public_peer_title" = "Public"; "lng_manage_peer_send_title" = "Who can send messages?"; "lng_manage_peer_send_only_members" = "Only members"; "lng_manage_peer_send_only_members_about" = "Turn this on if you expect users to join your group before being able to send messages."; "lng_manage_peer_send_approve_members" = "Approve new members"; "lng_manage_peer_send_approve_members_about" = "Turn this on if you want users to join the group only after they are approved by an admin."; "lng_manage_peer_no_forwards_title" = "Content protection"; "lng_manage_peer_no_forwards" = "Restrict saving content"; "lng_manage_peer_no_forwards_about" = "Members won't be able to copy, save or forward content from this group."; "lng_manage_peer_no_forwards_about_channel" = "Subscribers won't be able to copy, save or forward content from this channel."; "lng_disable_sharing" = "Disable Sharing"; "lng_enable_sharing" = "Enable Sharing"; "lng_disable_sharing_title" = "Disable Sharing"; "lng_disable_sharing_no_forwarding" = "No Forwarding"; "lng_disable_sharing_no_forwarding_about" = "Disable message forwarding to other chats."; "lng_disable_sharing_no_saving" = "No Saving"; "lng_disable_sharing_no_saving_about" = "Disable copying texts and saving photos and videos to gallery."; "lng_disable_sharing_unlock" = "Unlock with Telegram Premium"; "lng_disable_sharing_button" = "Disable Sharing"; "lng_disable_sharing_toast" = "Sharing disabled for this chat."; "lng_enable_sharing_toast" = "Sharing enabled for this chat."; "lng_enable_sharing_request_title" = "Enable Sharing"; "lng_enable_sharing_request_text" = "You need **{name}'s** approval to enable sharing. Send a request?"; "lng_enable_sharing_request_button" = "Send Request"; "lng_action_no_forwards_you_disabled" = "You disabled sharing in this chat"; "lng_action_no_forwards_you_enabled" = "You enabled sharing in this chat"; "lng_action_no_forwards_disabled" = "{from} disabled sharing in this chat"; "lng_action_no_forwards_enabled" = "{from} enabled sharing in this chat"; "lng_action_no_forwards_still_disabled" = "Sharing in this chat is still disabled"; "lng_action_no_forwards_request" = "{from} would like to enable sharing in this chat, which includes:"; "lng_action_no_forwards_request_you" = "You requested to enable sharing in this chat, which includes:"; "lng_action_no_forwards_feature_forwarding" = "Forwarding messages"; "lng_action_no_forwards_feature_saving" = "Saving photos and videos"; "lng_action_no_forwards_feature_copying" = "Copying messages"; "lng_action_no_forwards_accept" = "Accept"; "lng_action_no_forwards_reject" = "Reject"; "lng_action_no_forwards_request_expired" = "Sharing enable request has expired"; "lng_manage_peer_bot_public_link" = "Public Link"; "lng_manage_peer_bot_public_links" = "Public Links"; "lng_manage_peer_bot_balance" = "Balance"; "lng_manage_peer_bot_balance_currency" = "Toncoin"; "lng_manage_peer_bot_balance_credits" = "Stars"; "lng_manage_peer_bot_star_ref" = "Affiliate Program"; "lng_manage_peer_bot_star_ref_off" = "Off"; "lng_manage_peer_bot_star_ref_about" = "Share a link to {bot} with your friends and earn {amount} of their spending there."; "lng_manage_peer_bot_verify" = "Verify Accounts"; "lng_manage_peer_bot_edit_intro" = "Edit Intro"; "lng_manage_peer_bot_edit_commands" = "Edit Commands"; "lng_manage_peer_bot_edit_settings" = "Change Bot Settings"; "lng_manage_peer_bot_about" = "Use {bot} to manage this bot."; "lng_bot_verify_title" = "Choose Chat to Verify"; "lng_bot_verify_bot_title" = "Verify Bot"; "lng_bot_verify_bot_text" = "Do you want to verify {name} with your verification mark and description?"; "lng_bot_verify_bot_about" = "You can customize your description for each bot."; "lng_bot_verify_bot_submit" = "Verify Bot"; "lng_bot_verify_bot_sent" = "{name} has been notified and will receive your verification mark and description upon accepting."; "lng_bot_verify_bot_remove" = "This bot is already verified by you. Do you want to remove verification?"; "lng_bot_verify_user_title" = "Verify User"; "lng_bot_verify_user_text" = "Do you want to verify {name} with your verification mark and description?"; "lng_bot_verify_user_about" = "You can customize your description for each account."; "lng_bot_verify_user_submit" = "Verify User"; "lng_bot_verify_user_sent" = "{name} has been notified and will receive your verification mark and description upon accepting."; "lng_bot_verify_user_remove" = "This account is already verified by you. Do you want to remove verification?"; "lng_bot_verify_channel_title" = "Verify Channel"; "lng_bot_verify_channel_text" = "Do you want to verify {name} with your verification mark and description?"; "lng_bot_verify_channel_about" = "You can customize your description for each channel."; "lng_bot_verify_channel_submit" = "Verify Channel"; "lng_bot_verify_channel_sent" = "{name} has been notified and will receive your verification mark and description upon accepting."; "lng_bot_verify_channel_remove" = "This channel is already verified by you. Do you want to remove verification?"; "lng_bot_verify_group_title" = "Verify Group"; "lng_bot_verify_group_text" = "Do you want to verify {name} with your verification mark and description?"; "lng_bot_verify_group_about" = "You can customize your description for each group."; "lng_bot_verify_group_submit" = "Verify Group"; "lng_bot_verify_group_sent" = "{name} has been notified and will receive your verification mark and description upon accepting."; "lng_bot_verify_group_remove" = "This group is already verified by you. Do you want to remove verification?"; "lng_bot_verify_description_label" = "Description"; "lng_bot_verify_remove_title" = "Remove verification"; "lng_bot_verify_remove_submit" = "Remove"; "lng_bot_verify_remove_done" = "You've removed this verification."; "lng_star_ref_title" = "Affiliate Program"; "lng_star_ref_about" = "Reward those who help grow your user base."; "lng_star_ref_share_title" = "Share revenue with affiliates"; "lng_star_ref_share_about" = "Set the commission for revenue generated by users referred to you."; "lng_star_ref_launch_title" = "Launch your affiliate program"; "lng_star_ref_launch_about" = "Telegram will feature your program for millions of potential affiliates."; "lng_star_ref_let_title" = "Let affiliate promote you"; "lng_star_ref_let_about" = "Affiliates will share your referral link with their audience."; "lng_star_ref_commission_title" = "Commission"; "lng_star_ref_commission_about" = "Define the percentage of star revenue your affiliates earn for referring users to your bot."; "lng_star_ref_duration_title" = "Duration"; "lng_star_ref_duration_about" = "Set the duration for which affiliates will earn commissions from referred users."; "lng_star_ref_existing_title" = "View existing programs"; "lng_star_ref_existing_about" = "Explore what other mini apps offer."; "lng_star_ref_add_bot" = "Add {bot}"; "lng_star_ref_end" = "End Affiliate Program"; "lng_star_ref_start" = "Start Affiliate Program"; "lng_star_ref_start_disabled" = "Available in {time}"; "lng_star_ref_start_info" = "By creating an affiliate program, you agree to the {terms} of Affiliate Programs."; "lng_star_ref_update" = "Update Affiliate Program"; "lng_star_ref_update_info" = "By updating an affiliate program, you agree to the {terms} of Affiliate Programs."; "lng_star_ref_button_link" = "terms and conditions"; "lng_star_ref_tos_url" = "https://telegram.org/tos/mini-apps"; "lng_star_ref_warning_title" = "Warning"; "lng_star_ref_warning_text" = "Once you start the affiliate program, you won't be able to decrease its commission or duration. You can only increase these parameters or end the program, which will disable all previously distributed referral links."; "lng_star_ref_warning_change" = "This change is irreversible. You won't be able to reduce commission or duration. You can only increase these parameters or end the program, which will disable all previously shared referral links."; "lng_star_ref_warning_start" = "Start"; "lng_star_ref_warning_update" = "Update"; "lng_star_ref_warning_if_end" = "If you end your affiliate program:"; "lng_star_ref_warning_if_end1" = "Any referral links already shared will be disabled in **24** hours."; "lng_star_ref_warning_if_end2" = "All participating affiliates will be notified."; "lng_star_ref_warning_if_end3" = "You will be able to start a new affiliate program only in **24** hours."; "lng_star_ref_warning_end" = "End Anyway"; "lng_star_ref_created_title" = "Affiliate program started"; "lng_star_ref_created_text" = "Any Telegram user, channel owner or mini app developer can now join your program."; "lng_star_ref_updated_title" = "Affiliate program updated"; "lng_star_ref_updated_text" = "Any Telegram user, channel owner or mini app developer can join your program."; "lng_star_ref_ended_title" = "Affiliate program ended"; "lng_star_ref_ended_text" = "Participating affiliates have been notified. All referral links will be disabled in **24** hours."; "lng_star_ref_list_title" = "Affiliate Programs"; "lng_star_ref_list_about_channel" = "Promote mini apps to your subscribers and earn a share of their revenue in Stars."; "lng_star_ref_list_text" = "Earn a commission each time a user who first accessed a mini app through your referral link spends **Stars** within it."; "lng_star_ref_list_my" = "My Programs"; "lng_star_ref_list_my_open" = "Open App"; "lng_star_ref_list_my_copy" = "Copy Link"; "lng_star_ref_list_my_leave" = "Leave"; "lng_star_ref_list_subtitle" = "Programs"; "lng_star_ref_sort_text" = "Sort by {sort}"; "lng_star_ref_sort_profitability" = "Profitability"; "lng_star_ref_sort_date" = "Date"; "lng_star_ref_sort_revenue" = "Revenue"; "lng_star_ref_reliable_title" = "Reliable"; "lng_star_ref_reliable_about" = "Receive guaranteed commissions for spending by users you refer."; "lng_star_ref_transparent_title" = "Transparent"; "lng_star_ref_transparent_about" = "Track your commissions from referred users in real time."; "lng_star_ref_simple_title" = "Simple"; "lng_star_ref_simple_about" = "Choose a mini app below, get your referral link, and start earning Stars."; "lng_star_ref_duration_forever" = "Forever"; "lng_star_ref_one_about" = "{app} will share {amount} of the revenue from each user you refer to it {duration}."; "lng_star_ref_one_about_for_forever" = "for **lifetime**"; "lng_star_ref_one_about_for_months#one" = "for **{count} month**"; "lng_star_ref_one_about_for_months#other" = "for **{count} months**"; "lng_star_ref_one_about_for_years#one" = "for **{count} year**"; "lng_star_ref_one_about_for_years#other" = "for **{count} years**"; "lng_star_ref_one_daily_revenue" = "Daily revenue per user: {amount}"; "lng_star_ref_one_join" = "Join Program"; "lng_star_ref_one_join_text" = "By joining this program, you agree to the {terms} of Affiliate Programs."; "lng_star_ref_joined_title" = "Program joined"; "lng_star_ref_joined_text" = "You can now copy the referral link."; "lng_star_ref_link_title" = "Referral Link"; "lng_star_ref_link_about_channel" = "Share this link with your subscribers to earn a {amount} commission on their spending in {app} {duration}."; "lng_star_ref_link_about_user" = "Share this link with your friends to earn a {amount} commission on their spending in {app} {duration}."; "lng_star_ref_link_about_bot" = "Share this link with your users to earn a {amount} commission on their spending in {app} {duration}."; "lng_star_ref_link_recipient" = "Commissions will be sent to:"; "lng_star_ref_link_copy" = "Copy Link"; "lng_star_ref_link_copy_none" = "No one have opened {app} through this link."; "lng_star_ref_link_copy_users#one" = "{count} user have opened {app} through this link."; "lng_star_ref_link_copy_users#other" = "{count} users have opened {app} through this link."; "lng_star_ref_link_copied_title" = "Link copied to clipboard"; "lng_star_ref_link_copied_text" = "Share this link and earn {amount} of what people who use it spend in {app}!"; "lng_star_ref_stopped" = "This affiliate link is no longer active."; "lng_star_ref_revoke_title" = "Revoke Link"; "lng_star_ref_revoke_text" = "Are you sure you want to revoke the link of {bot}?"; "lng_star_ref_revoked_title" = "Link removed"; "lng_star_ref_revoked_text" = "It will no longer work."; "lng_stars_rating_title" = "Rating"; "lng_stars_rating_future" = "Future Rating"; "lng_stars_rating_updates#one" = "in {count} day"; "lng_stars_rating_updates#other" = "in {count} days"; "lng_stars_rating_pending#one" = "The rating will update {when}.\n{count} point is pending. {link}"; "lng_stars_rating_pending#other" = "The rating will update {when}.\n{count} points are pending. {link}"; "lng_stars_rating_pending_preview" = "Preview {arrow}"; "lng_stars_rating_pending_back" = "Back {arrow}"; "lng_stars_rating_negative_label" = "Negative Rating"; "lng_stars_rating_negative" = "A negative rating indicates that **{name}'s** payments are unreliable."; "lng_stars_rating_negative_your#one" = "A negative rating indicates that your payments are unreliable. Spend **{count} Star** to fix this issue."; "lng_stars_rating_negative_your#other" = "A negative rating indicates that your payments are unreliable. Spend **{count} Stars** to fix this issue."; "lng_stars_rating_about" = "This rating reflects **{name}'s** activity on Telegram. What affects it:"; "lng_stars_rating_about_your" = "This rating reflects your activity on Telegram. What affects it:"; "lng_stars_title_gifts_telegram" = "Gifts from Telegram"; "lng_stars_about_gifts_telegram" = "{emoji} 100% of the Stars spent on gifts purchased from Telegram."; "lng_stars_title_gifts_users" = "Gifts and Posts from Users"; "lng_stars_about_gifts_users" = "{emoji} 20% of the Stars spent on resold gifts, paid messages and channel posts."; "lng_stars_title_refunds" = "Refunds and Conversions"; "lng_stars_about_refunds" = "{emoji} 10x of refunded Stars and 85% of bought gifts converted to Stars."; "lng_stars_rating_added" = "Added"; "lng_stars_rating_deducted" = "Deducted"; "lng_stars_rating_understood" = "Understood"; "lng_manage_discussion_group" = "Discussion"; "lng_manage_discussion_group_add" = "Add a group"; "lng_manage_linked_channel" = "Linked channel"; "lng_manage_linked_channel_restore" = "Restore linked channel"; "lng_manage_discussion_group_about" = "Select a group chat for discussion that will be displayed in your channel."; "lng_manage_discussion_group_about_chosen" = "A link to {group} is shown to all subscribers in the bottom panel."; "lng_manage_discussion_group_create" = "Create a new group"; "lng_manage_discussion_group_unlink" = "Unlink group"; "lng_manage_discussion_group_posted" = "Everything you post in the channel is forwarded to this group."; "lng_manage_discussion_group_sure" = "Do you want to make {group} the discussion board for {channel}?"; "lng_manage_linked_channel_private" = "Any member of this group will be able to see messages in the channel."; "lng_manage_discussion_group_private" = "Anyone from the channel will be able to see messages in this group."; "lng_manage_discussion_group_link" = "Link group"; "lng_manage_linked_channel_private_status" = "private channel"; "lng_manage_discussion_group_private_status" = "private group"; "lng_manage_linked_channel_about" = "This group is linked as the discussion board for {channel}."; "lng_manage_linked_channel_unlink" = "Unlink channel"; "lng_manage_linked_channel_posted" = "All new posts from this channel are forwarded to the group."; "lng_manage_discussion_group_warning" = "\"Chat history for new members\" will be switched to **Visible**."; "lng_manage_monoforum" = "Direct Messages"; "lng_manage_monoforum_off" = "Off"; "lng_manage_monoforum_free" = "Free"; "lng_manage_monoforum_allow" = "Allow Channel Messages"; "lng_manage_monoforum_price" = "Price for each message"; "lng_manage_monoforum_about" = "Allow users to send messages to your channel, with the option to charge a fee for each message."; "lng_manage_monoforum_price_about" = "Your channel will receive {percent} of the selected fee ({amount}) for each incoming message."; "lng_manage_monoforum_link_subtitle" = "Link to direct messages"; "lng_manage_history_visibility_title" = "Chat history for new members"; "lng_manage_history_visibility_shown" = "Visible"; "lng_manage_history_visibility_shown_about" = "New members will see messages that were sent before they joined."; "lng_manage_history_visibility_hidden" = "Hidden"; "lng_manage_history_visibility_hidden_about" = "New members won't see earlier messages."; "lng_manage_history_visibility_hidden_legacy" = "New members won't see more than 100 previous messages."; "lng_manage_messages_ttl_title" = "Auto-delete messages"; "lng_manage_messages_ttl_disable" = "Disable"; "lng_manage_messages_ttl_after1" = "1 day"; "lng_manage_messages_ttl_after2" = "1 week"; "lng_manage_messages_ttl_after3" = "1 month"; "lng_manage_messages_ttl_after4" = "1 month"; "lng_manage_messages_ttl_after_custom" = "Custom"; "lng_manage_messages_ttl_menu" = "Auto-Delete"; "lng_ttl_edit_about" = "Automatically delete new messages for you and {user} after a certain period of time."; "lng_ttl_edit_about_group" = "Automatically delete new messages sent in this chat after a certain period of time."; "lng_ttl_edit_about_channel" = "Automatically delete new messages sent in this channel after a certain period of time."; "lng_ttl_edit_about2" = "You can also set a default {link} for all your chats in Settings."; "lng_ttl_edit_about2_link" = "self-destruct timer"; "lng_ttl_about_tooltip" = "New messages in this chat will be automatically deleted after {duration}."; "lng_ttl_about_tooltip_channel" = "New messages in this chat will be automatically deleted after {duration}."; "lng_ttl_about_tooltip_off" = "Auto-delete is now disabled."; "lng_report_title" = "Report channel"; "lng_report_group_title" = "Report Group"; "lng_report_bot_title" = "Report bot"; "lng_report_message_title" = "Report message"; "lng_report_profile_photo_title" = "Report profile photo"; "lng_report_profile_video_title" = "Report profile photo"; "lng_report_group_photo_title" = "Report group photo"; "lng_report_group_video_title" = "Report group photo"; "lng_report_channel_photo_title" = "Report channel photo"; "lng_report_channel_video_title" = "Report channel photo"; "lng_report_story" = "Report story"; "lng_report_please_select_messages" = "Please select messages to report."; "lng_report_select_messages" = "Select messages"; "lng_report_messages_none" = "Select Messages"; "lng_report_messages_count#one" = "Report {count} Message"; "lng_report_messages_count#other" = "Report {count} Messages"; "lng_report_reaction" = "Report reaction"; "lng_report_and_ban" = "Ban and report"; "lng_report_reaction_title" = "Report reaction"; "lng_report_reaction_about" = "Are you sure you want to report reactions from this user?"; "lng_report_and_ban_button" = "Ban user"; "lng_report_details_about" = "Please enter any additional details relevant to your report."; "lng_report_details" = "Additional Details"; "lng_report_details_optional" = "Add Comment (Optional)"; "lng_report_details_non_optional" = "Add Comment"; "lng_report_details_message_about" = "Please help us by telling what is wrong with the message you have selected"; "lng_report_reason_spam" = "Spam"; "lng_report_reason_fake" = "Fake Account"; "lng_report_reason_violence" = "Violence"; "lng_report_reason_child_abuse" = "Child Abuse"; "lng_report_reason_pornography" = "Pornography"; "lng_report_reason_copyright" = "Copyright"; "lng_report_reason_illegal_drugs" = "Illegal Drugs"; "lng_report_reason_personal_details" = "Personal Details"; "lng_report_reason_other" = "Other"; "lng_report_button" = "Report"; "lng_report_thanks" = "Thank you! Your report will be reviewed by our team."; "lng_report_sponsored_hidden" = "Sponsored messages will be hidden."; "lng_report_sponsored_reported" = "We will review this ad to ensure it matches our {link}."; "lng_report_sponsored_reported_link" = "Ad Policies and Guidelines"; "lng_report_sponsored_reported_learn" = "Learn more about our {link}."; "lng_channel_add_members" = "Add members"; "lng_channel_add_users" = "Add users"; "lng_channel_add_removed" = "Remove user"; "lng_channel_add_exception" = "Add exception"; "lng_channel_admins" = "Administrators"; "lng_channel_add_admin" = "Add Administrator"; "lng_channel_admin_status_creator" = "Owner"; "lng_channel_admin_status_promoted_by" = "Promoted by {user}"; "lng_channel_admin_status_not_admin" = "not admin"; "lng_channel_banned_status_restricted_by" = "Restricted by {user}"; "lng_channel_banned_status_removed_by" = "Removed by {user}"; "lng_channel_removed_list_about" = "Users removed from the channel by admins can't rejoin via invite links."; "lng_group_removed_list_about" = "Users removed from the group by admins can't rejoin via invite links."; "lng_participant_filter" = "Search"; "lng_participant_invite" = "Add"; "lng_participant_invite_history" = "Show the last 100 messages"; "lng_participant_invite_sure" = "Are you sure you want to add **{user}** to **{group}**?"; "lng_participant_invite_sure_many#one" = "Are you sure you want to add {count} member to **{group}**?"; "lng_participant_invite_sure_many#other" = "Are you sure you want to add {count} members to **{group}**?"; "lng_participant_invite_sorry#one" = "Sorry, you can only add the first {count} subscriber to a channel personally.\n\nFrom now on, people will need to join via your invite link."; "lng_participant_invite_sorry#other" = "Sorry, you can only add the first {count} subscribers to a channel personally.\n\nFrom now on, people will need to join via your invite link."; "lng_create_group_back" = "Back"; "lng_create_group_next" = "Next"; "lng_create_group_create" = "Create"; "lng_create_group_title" = "New Group"; "lng_create_channel_title" = "New Channel"; "lng_create_public_channel_title" = "Public Channel"; "lng_create_public_channel_about" = "Anyone can find the channel in search and join"; "lng_create_private_channel_title" = "Private Channel"; "lng_create_private_channel_about" = "Only people with an invite link can join."; "lng_create_public_group_title" = "Public Group"; "lng_create_public_group_about" = "Anyone can find the group in search and join, chat history is available to everybody"; "lng_create_private_group_title" = "Private Group"; "lng_create_private_group_about" = "People can only join if they are added or have an invite link"; "lng_create_permanent_link_title" = "Primary link"; "lng_create_invite_link_title" = "Invite link"; "lng_create_invite_link_about" = "People can be added, or join via invite link or \"Groups nearby\""; "lng_create_group_skip" = "Skip"; "lng_create_channel_link_about" = "You can use a-z, 0-9 and underscores.\nMinimum length is 5 characters."; "lng_create_channel_link_invalid" = "This link is invalid"; "lng_create_channel_link_occupied" = "Sorry, this link is already occupied"; "lng_create_channel_link_too_short" = "Sorry, this link is too short"; "lng_create_channel_link_bad_symbols" = "Only 0-9, a-z, and underscores allowed."; "lng_create_channel_link_available" = "This link is available"; "lng_create_channel_link_pending" = "Checking name..."; "lng_create_channel_link_copied" = "Link copied to clipboard."; "lng_failed_add_participant" = "Could not add user. Please try again later."; "lng_failed_add_not_mutual" = "Sorry, if a person is no longer part of a group, you need to add each other to your respective contact lists to be able to add them back.\n\nNote that they could still join via the group's invite link as long as they are not in the Removed users list."; "lng_sure_delete_contact" = "Are you sure you want to delete {contact} from your contact list?"; "lng_sure_delete_history" = "Are you sure you want to delete all message history with {contact}?\n\nThis action cannot be undone."; "lng_sure_delete_group_history" = "Are you sure you want to delete all messages in \"{group}\"?\n\nThis action cannot be undone."; "lng_sure_delete_channel_history" = "Are you sure you want to delete all messages in \"{channel}\"?\n\n**This action cannot be undone.**"; "lng_sure_delete_and_exit" = "Are you sure you want to delete all message history and leave «{group}»?\n\nThis action cannot be undone."; "lng_sure_leave_channel" = "Are you sure you want to leave\nthis channel?"; "lng_sure_delete_channel" = "Are you sure you want to delete this channel? All subscribers will be removed and all messages will be lost."; "lng_sure_leave_group" = "Are you sure you want to leave this group?"; "lng_sure_delete_group" = "Are you sure you want to delete this group? All members will be removed, and all messages will be lost."; "lng_sure_delete_saved_messages" = "Are you sure you want to delete all your saved messages?\n\nThis action cannot be undone."; "lng_no_clear_history_channel" = "In channels you can enable auto-delete for messages."; "lng_no_clear_history_group" = "In public groups you can enable auto-delete for messages."; "lng_sure_delete_by_date_one" = "Are you sure you want to delete all messages for **{date}**?\n\nThis action cannot be undone."; "lng_sure_delete_by_date_many" = "Are you sure you want to delete all messages for the **{days}**?\n\nThis action cannot be undone."; "lng_sure_delete_selected_days#one" = "{count} selected day"; "lng_sure_delete_selected_days#other" = "{count} selected days"; "lng_message_empty" = "Empty Message"; "lng_message_unsupported" = "This message is not supported by your version of Telegram. Please update to the latest version in Settings > Advanced, or install it from {link}. If you are already using the latest version, this message might depend on a feature that is not yet implemented."; "lng_message_not_found" = "Message doesn't exist."; "lng_duration_minsec_minutes#one" = "{count} min"; "lng_duration_minsec_minutes#other" = "{count} min"; "lng_duration_minsec_seconds#one" = "{count} s"; "lng_duration_minsec_seconds#other" = "{count} s"; "lng_duration_minutes_seconds" = "{minutes_count} {seconds_count}"; "lng_action_invite_user" = "{from} invited {user} to {chat}"; "lng_action_invite_users_many" = "{from} invited {users} to {chat}"; "lng_action_invite_user_chat" = "the video chat"; "lng_action_invite_users_and_one" = "{accumulated}, {user}"; "lng_action_invite_users_and_last" = "{accumulated} and {user}"; "lng_action_group_call_started_group" = "{from} started a video chat"; "lng_action_group_call_started_channel" = "Live stream started"; "lng_action_group_call_scheduled_group" = "{from} scheduled a video chat for {date}"; "lng_action_group_call_scheduled_channel" = "Live stream scheduled for {date}"; "lng_action_group_call_finished" = "Live stream finished ({duration})"; "lng_action_group_call_finished_group" = "{from} ended the video chat ({duration})"; "lng_action_add_user" = "{from} added {user}"; "lng_action_add_users_many" = "{from} added {users}"; "lng_action_add_users_and_one" = "{accumulated}, {user}"; "lng_action_add_users_and_last" = "{accumulated} and {user}"; "lng_action_add_you" = "{from} added you to this channel"; "lng_action_you_joined" = "You joined this channel"; "lng_action_add_you_group" = "{from} added you to this group"; "lng_action_kick_user" = "{from} removed {user}"; "lng_action_user_left" = "{from} left the group"; "lng_action_user_joined" = "{from} joined the group"; "lng_action_user_joined_by_link" = "{from} joined the group via invite link"; "lng_action_user_joined_by_request" = "{from} was accepted to the group"; "lng_action_you_joined_by_request" = "Your request to join the group was approved"; "lng_action_you_joined_by_request_channel" = "Your request to join the channel was approved"; "lng_action_user_registered" = "{from} joined Telegram"; "lng_action_removed_photo" = "{from} removed group photo"; "lng_action_removed_photo_channel" = "Channel photo removed"; "lng_action_changed_photo" = "{from} updated group photo"; "lng_action_changed_photo_channel" = "Channel photo updated"; "lng_action_changed_title" = "{from} changed group name to «{title}»"; "lng_action_changed_title_channel" = "Channel name was changed to «{title}»"; "lng_action_created_chat" = "{from} created the group «{title}»"; "lng_action_created_monoforum" = "Direct messages were enabled in this channel."; "lng_action_ttl_changed" = "{from} set messages to auto-delete in {duration}"; "lng_action_ttl_changed_you" = "You set messages to auto-delete in {duration}"; "lng_action_ttl_changed_channel" = "Messages in this channel will be automatically deleted after {duration}"; "lng_action_ttl_global" = "{from} uses a self-destruct timer for all chats. All new messages in this chat will be automatically deleted after {duration} they are sent."; "lng_action_ttl_global_me" = "You set a self-destruct timer for all chats. All new messages in this chat will be automatically deleted after {duration} they’ve been sent."; "lng_action_ttl_removed" = "{from} disabled the auto-delete timer"; "lng_action_ttl_removed_you" = "You disabled the auto-delete timer"; "lng_action_ttl_removed_channel" = "Messages in this channel will no longer be automatically deleted"; "lng_action_created_channel" = "Channel created"; "lng_action_pinned_message" = "{from} pinned \"{text}\""; "lng_action_pinned_media" = "{from} pinned {media}"; "lng_action_pinned_media_photo" = "a photo"; "lng_action_pinned_media_video" = "a video"; "lng_action_pinned_media_audio" = "an audio file"; "lng_action_pinned_media_voice" = "a voice message"; "lng_action_pinned_media_video_message" = "a video message"; "lng_action_pinned_media_file" = "a file"; "lng_action_pinned_media_gif" = "a GIF"; "lng_action_pinned_media_contact" = "a contact information"; "lng_action_pinned_media_location" = "a location mark"; "lng_action_pinned_media_sticker" = "a sticker"; "lng_action_pinned_media_emoji_sticker" = "a {emoji} sticker"; "lng_action_pinned_media_game" = "the game «{game}»"; "lng_action_pinned_media_story" = "a story"; "lng_action_game_score#one" = "{from} scored {count} in {game}"; "lng_action_game_score#other" = "{from} scored {count} in {game}"; "lng_action_game_you_scored#one" = "You scored {count} in {game}"; "lng_action_game_you_scored#other" = "You scored {count} in {game}"; "lng_action_game_score_no_game#one" = "{from} scored {count}"; "lng_action_game_score_no_game#other" = "{from} scored {count}"; "lng_action_game_you_scored_no_game#one" = "You scored {count}"; "lng_action_game_you_scored_no_game#other" = "You scored {count}"; "lng_action_payment_done" = "You successfully transferred {amount} to {user}"; "lng_action_payment_done_for" = "You successfully transferred {amount} to {user} for {invoice}"; "lng_action_payment_init_recurring_for" = "You successfully transferred {amount} to {user} for {invoice} and allowed future recurring payments"; "lng_action_payment_init_recurring" = "You successfully transferred {amount} to {user} and allowed future recurring payments"; "lng_action_payment_used_recurring" = "You were charged {amount} via recurring payment"; "lng_action_payment_bot_done" = "Bot connected to this account received {amount}"; "lng_action_payment_bot_recurring" = "Bot connected to this account received {amount} via recurring payment"; "lng_action_took_screenshot" = "{from} took a screenshot!"; "lng_action_you_took_screenshot" = "You took a screenshot!"; "lng_action_bot_allowed_from_domain" = "You allowed this bot to message you when you logged in on {domain}."; "lng_action_bot_allowed_from_app" = "You allowed this bot to message you when you opened {app}."; "lng_action_secure_values_sent" = "{user} received the following documents: {documents}"; "lng_action_secure_personal_details" = "personal details"; "lng_action_secure_proof_of_identity" = "proof of identity"; "lng_action_secure_address" = "address"; "lng_action_secure_proof_of_address" = "proof of address"; "lng_action_secure_phone" = "phone number"; "lng_action_secure_email" = "email address"; "lng_action_proximity_reached" = "{from} is now within {distance} from {user}"; "lng_action_proximity_reached_you" = "{from} is now within {distance} from you"; "lng_action_you_proximity_reached" = "You are now within {distance} from {user}"; "lng_action_you_theme_changed" = "You changed the chat theme to {emoji}"; "lng_action_theme_changed" = "{from} changed the chat theme to {emoji}"; "lng_action_you_gift_theme_changed" = "You set {name} as a new theme for this chat."; "lng_action_gift_theme_changed" = "{from} set {name} as a new theme for this chat."; "lng_action_you_theme_disabled" = "You disabled the chat theme"; "lng_action_theme_disabled" = "{from} disabled the chat theme"; "lng_action_proximity_distance_m#one" = "{count} meter"; "lng_action_proximity_distance_m#other" = "{count} meters"; "lng_action_proximity_distance_km#one" = "{count} km"; "lng_action_proximity_distance_km#other" = "{count} km"; "lng_action_webview_data_done" = "Data from the \"{text}\" button was transferred to the bot."; "lng_action_gift_received" = "{user} sent you a gift for {cost}"; "lng_action_gift_received_sold" = "{user} sold you a gift for {cost}"; "lng_action_gift_unique_received" = "{user} sent you a unique collectible item"; "lng_action_gift_sent" = "You sent a gift for {cost}"; "lng_action_gift_sent_sold" = "You sold a gift for {cost}"; "lng_action_gift_unique_sent" = "You sent a unique collectible item"; "lng_action_gift_upgraded" = "{user} turned the gift from you into a unique collectible"; "lng_action_gift_upgraded_channel" = "{user} turned this gift to {channel} into a unique collectible"; "lng_action_gift_upgraded_self_channel" = "You turned this gift to {channel} into a unique collectible"; "lng_action_gift_upgraded_mine" = "You turned the gift from {user} into a unique collectible"; "lng_action_gift_upgraded_self" = "You turned this gift into a unique collectible"; "lng_action_gift_sent_upgrade_other" = "{from} sent an upgrade worth {cost} for the gift you received from {user}."; "lng_action_gift_sent_upgrade_self_other" = "You sent an upgrade worth {cost} for the gift {name} received from {user}."; "lng_action_gift_sent_upgrade" = "{from} sent an upgrade worth {cost} for your gift."; "lng_action_gift_sent_upgrade_self" = "You sent an upgrade worth {cost} for this gift."; "lng_action_gift_sent_upgrade_self_channel" = "You sent an upgrade worth {cost} for your gift to {name}."; "lng_action_gift_upgraded_helped" = "{user} unpacked the gift that you helped to upgrade."; "lng_action_gift_upgraded_helped_self" = "You unpacked the gift that {user} helped to upgrade."; "lng_action_gift_transferred" = "{user} transferred you a gift"; "lng_action_gift_transferred_channel" = "{user} transferred a gift to {channel}"; "lng_action_gift_transferred_unknown" = "Someone transferred you a gift"; "lng_action_gift_transferred_unknown_channel" = "Someone transferred a gift to {channel}"; "lng_action_gift_transferred_self" = "You transferred a unique collectible"; "lng_action_gift_displayed_self" = "You've started displaying {name} on your Telegram profile page."; "lng_action_gift_transferred_self_channel" = "You transferred a gift to {channel}"; "lng_action_gift_transferred_mine" = "You transferred a gift to {user}"; "lng_action_gift_crafted" = "You crafted a new gift"; "lng_action_gift_received_anonymous" = "Unknown user sent you a gift for {cost}"; "lng_action_gift_sent_channel" = "{user} sent a gift to {name} for {cost}"; "lng_action_gift_sent_self_channel" = "You sent a gift to {name} for {cost}"; "lng_action_gift_self_bought" = "You bought a gift for {cost}"; "lng_action_gift_self_auction" = "You've successfully bought a gift in the auction for {cost}."; "lng_action_gift_auction_won" = "You won the auction with a bid of {cost}."; "lng_action_gift_self_subtitle" = "Saved Gift"; "lng_action_gift_crafted_subtitle" = "Crafted Gift"; "lng_action_gift_self_about#one" = "Display this gift on your page or convert it to **{count}** Star."; "lng_action_gift_self_about#other" = "Display this gift on your page or convert it to **{count}** Stars."; "lng_action_gift_self_about_unique" = "You can display this gift on your page or turn it into unique collectible and send to others."; "lng_action_gift_channel_about#one" = "Display this gift in channel's Gifts or convert it to **{count}** Star."; "lng_action_gift_channel_about#other" = "Display this gift in channel's Gifts or convert it to **{count}** Stars."; "lng_action_gift_channel_about_unique" = "You can display this gift in channel's Gifts or turn it into unique collectible."; "lng_action_gift_for_stars#one" = "{count} Star"; "lng_action_gift_for_stars#other" = "{count} Stars"; "lng_action_gift_for_ton#one" = "{count} TON"; "lng_action_gift_for_ton#other" = "{count} TON"; "lng_action_gift_got_subtitle" = "Gift from {user}"; "lng_action_gift_got_stars_text#one" = "Display this gift on your page or convert it to **{count}** Star."; "lng_action_gift_got_stars_text#other" = "Display this gift on your page or convert it to **{count}** Stars."; "lng_action_gift_got_upgradable_text" = "Upgrade this gift to a unique collectible."; "lng_action_gift_got_gift_text" = "You can keep this gift on your page."; "lng_action_gift_can_remove_text" = "You can remove this gift from your page."; "lng_action_gift_got_gift_channel" = "You can keep this gift in channel's Gifts."; "lng_action_gift_can_remove_channel" = "You can remove this gift from channel's Gifts."; "lng_action_gift_sent_subtitle" = "Gift for {user}"; "lng_action_gift_sent_text#one" = "{user} can display this gift on their page or convert it to {count} Star."; "lng_action_gift_sent_text#other" = "{user} can display this gift on their page or convert it to {count} Stars."; "lng_action_gift_sent_upgradable" = "{user} can upgrade this gift to a unique collectible."; "lng_action_gift_premium_months#one" = "{count} Month Premium"; "lng_action_gift_premium_months#other" = "{count} Months Premium"; "lng_action_gift_premium_about" = "Subscription for exclusive Telegram features."; "lng_action_gift_refunded" = "This gift was downgraded because a request to refund the payment related to this gift was made, and the money was returned."; "lng_action_gift_got_ton" = "Use TON to suggest posts to channels."; "lng_action_gift_offer_incoming" = "An offer to buy this gift for {amount}."; "lng_action_gift_offer_you" = "You offered {cost} for {name}."; "lng_action_gift_offer_state_expires" = "This offer expires in {time}."; "lng_action_gift_offer_time_large" = "{hours} h"; "lng_action_gift_offer_time_medium" = "{hours} h {minutes} m"; "lng_action_gift_offer_time_small" = "{minutes} m"; "lng_action_gift_offer_state_accepted" = "This offer was accepted."; "lng_action_gift_offer_state_rejected" = "This offer was rejected."; "lng_action_gift_offer_state_expired" = "This offer has expired."; "lng_action_gift_offer_sold" = "{user} sold {name} for {cost}."; "lng_action_gift_offer_sold_you" = "You sold {name} for {cost}."; "lng_action_gift_offer_decline" = "Reject"; "lng_action_gift_offer_accept" = "Accept"; "lng_action_gift_offer_expired" = "The offer from {user} to buy your {name} for {cost} has expired."; "lng_action_gift_offer_expired_your" = "Your offer to buy {name} for {cost} has expired."; "lng_action_gift_offer_declined" = "{user} rejected your offer to buy {name} for {cost}."; "lng_action_gift_offer_declined_you" = "You rejected {user}'s offer to buy your {name} for {cost}."; "lng_action_suggested_photo_me" = "You suggested this photo for {user}'s Telegram profile."; "lng_action_suggested_photo" = "{user} suggests this photo for your Telegram profile."; "lng_action_suggested_photo_button" = "View Photo"; "lng_action_suggested_video_me" = "You suggested this photo for {user}'s Telegram profile."; "lng_action_suggested_video" = "{user} suggests this photo for your Telegram profile."; "lng_action_suggested_video_button" = "View Photo"; "lng_action_suggested_birthday_me" = "You suggest {user} add a date of birth:"; "lng_action_suggested_birthday" = "{user} suggests you add your date of birth:"; "lng_action_suggested_birtday_button" = "View"; "lng_action_attach_menu_bot_allowed" = "You allowed this bot to message you when you added it to your attachment menu."; "lng_action_webapp_bot_allowed" = "You allowed this bot to message you in its web-app."; "lng_action_set_wallpaper_me" = "You set a new wallpaper for this chat"; "lng_action_set_wallpaper" = "{user} set a new wallpaper for this chat"; "lng_action_set_wallpaper_both_me" = "You set a new wallpaper for {user} and you."; "lng_action_set_wallpaper_button" = "View Wallpaper"; "lng_action_set_wallpaper_remove" = "Remove"; "lng_action_set_same_wallpaper_me" = "You set the same wallpaper as your chat partner"; "lng_action_set_same_wallpaper" = "{user} set the same wallpaper for this chat"; "lng_action_topic_created_inside" = "Topic created"; "lng_action_topic_closed_inside" = "Topic closed"; "lng_action_topic_reopened_inside" = "Topic reopened"; "lng_action_topic_closed_inside_by" = "{from} closed the topic"; "lng_action_topic_reopened_inside_by" = "{from} reopened the topic"; "lng_action_topic_hidden_inside" = "Topic hidden"; "lng_action_topic_unhidden_inside" = "Topic unhidden"; "lng_action_topic_created" = "The topic \"{topic}\" was created"; "lng_action_topic_closed" = "\"{topic}\" was closed"; "lng_action_topic_reopened" = "\"{topic}\" was reopened"; "lng_action_topic_closed_by" = "{from} closed \"{topic}\""; "lng_action_topic_reopened_by" = "{from} reopened \"{topic}\""; "lng_action_topic_hidden" = "\"{topic}\" was hidden"; "lng_action_topic_unhidden" = "\"{topic}\" was unhidden"; "lng_action_topic_placeholder" = "topic"; "lng_action_topic_bot_thread" = "thread"; "lng_action_topic_renamed" = "{from} renamed the {link} to \"{title}\""; "lng_action_topic_icon_changed" = "{from} changed the {link} icon to {emoji}"; "lng_action_topic_icon_removed" = "{from} removed the {link} icon"; "lng_action_shared_chat_with_bot" = "You shared {chat} with {bot}"; "lng_action_story_mention_me" = "You mentioned {user} in a story"; "lng_action_story_mention" = "{user} mentioned you in a story"; "lng_action_story_mention_button" = "View Story"; "lng_action_story_mention_me_unavailable" = "The story where you mentioned {user} is no longer available."; "lng_action_story_mention_unavailable" = "The story where {user} mentioned you is no longer available."; "lng_action_giveaway_started_group" = "{from} just started a giveaway of Telegram Premium subscriptions to its members."; "lng_action_giveaway_started" = "{from} just started a giveaway of Telegram Premium subscriptions for its followers."; "lng_action_giveaway_credits_started_amount#one" = "{count} Star"; "lng_action_giveaway_credits_started_amount#other" = "{count} Stars"; "lng_action_giveaway_credits_started_group" = "{from} just started a giveaway of {amount} to its members."; "lng_action_giveaway_credits_started" = "{from} just started a giveaway of {amount} to its followers."; "lng_action_giveaway_results#one" = "{count} winner of the giveaway was randomly selected by Telegram and received private messages with giftcodes."; "lng_action_giveaway_results#other" = "{count} winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes."; "lng_action_giveaway_results_some" = "Some winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes."; "lng_action_giveaway_results_credits#one" = "{count} winner of the giveaway was randomly selected by Telegram and received their prize."; "lng_action_giveaway_results_credits#other" = "{count} winners of the giveaway were randomly selected by Telegram and received their prize."; "lng_action_giveaway_results_credits_some" = "Some winners of the giveaway were randomly selected by Telegram and received their prize."; "lng_action_giveaway_results_none" = "No winners of the giveaway could be selected."; "lng_action_boost_apply_me" = "You boosted the group"; "lng_action_boost_apply#one" = "{from} boosted the group"; "lng_action_boost_apply#other" = "{from} boosted the group {count} times"; "lng_action_set_chat_intro" = "{from} added the message below for all empty chats. How?"; "lng_action_payment_refunded" = "{peer} refunded {amount}"; "lng_action_paid_message_sent#one" = "You paid {count} Star to {action}"; "lng_action_paid_message_sent#other" = "You paid {count} Stars to {action}"; "lng_action_paid_message_one" = "send a message"; "lng_action_paid_message_some#one" = "send {count} message"; "lng_action_paid_message_some#other" = "send {count} messages"; "lng_action_paid_message_got#one" = "You received {count} Star from {name}"; "lng_action_paid_message_got#other" = "You received {count} Stars from {name}"; "lng_action_paid_message_refund#one" = "{from} refunded {count} Star to you"; "lng_action_paid_message_refund#other" = "{from} refunded {count} Stars to you"; "lng_action_paid_message_refund_self#one" = "You refunded {count} Star to {name}"; "lng_action_paid_message_refund_self#other" = "You refunded {count} Stars to {name}"; "lng_action_message_price_free" = "Messages are now free in this group."; "lng_action_message_price_paid#one" = "Messages now cost {count} Star each in this group."; "lng_action_message_price_paid#other" = "Messages now cost {count} Stars each in this group."; "lng_action_direct_messages_enabled" = "Channel enabled Direct Messages."; "lng_action_direct_messages_paid#one" = "Channel allows Direct Messages for {count} Star each."; "lng_action_direct_messages_paid#other" = "Channel allows Direct Messages for {count} Stars each."; "lng_action_direct_messages_disabled" = "Channel disabled Direct Messages."; "lng_action_todo_marked_done" = "{from} marked {tasks} as done."; "lng_action_todo_marked_done_self" = "You marked {tasks} as done."; "lng_action_todo_marked_not_done" = "{from} marked {tasks} as not done."; "lng_action_todo_marked_not_done_self" = "You marked {tasks} as not done."; "lng_action_todo_added" = "{from} added {tasks} to the list."; "lng_action_todo_added_self" = "You added {tasks} to the list."; "lng_action_poll_added_answer" = "{from} added \"{option}\" to the poll."; "lng_action_poll_added_answer_self" = "You added \"{option}\" to the poll."; "lng_action_poll_deleted_answer" = "{from} removed \"{option}\" from the poll."; "lng_action_poll_deleted_answer_self" = "You removed \"{option}\" from the poll."; "lng_action_todo_tasks_fallback#one" = "task"; "lng_action_todo_tasks_fallback#other" = "{count} tasks"; "lng_action_todo_tasks_and_one" = "{tasks}, {task}"; "lng_action_todo_tasks_and_last" = "{tasks} and {task}"; "lng_action_suggest_success_stars#one" = "{from} has received {count} Star for publishing post."; "lng_action_suggest_success_stars#other" = "{from} has received {count} Stars for publishing post."; "lng_action_suggest_success_ton#one" = "{from} has received {count} TON for publishing post."; "lng_action_suggest_success_ton#other" = "{from} has received {count} TON for publishing post."; "lng_action_suggest_refund_user" = "User refunded the Stars so that post was deleted."; "lng_action_suggest_refund_admin" = "Admin deleted the post early so that the price was refunded to the user."; "lng_action_post_rejected" = "The post was rejected."; "lng_action_not_enough_funds" = "Transaction failed."; "lng_you_paid_stars#one" = "You paid {count} Star."; "lng_you_paid_stars#other" = "You paid {count} Stars."; "lng_action_stake_game_nothing" = "{from} didn't win anything"; "lng_action_stake_game_nothing_you" = "You didn't win anything"; "lng_action_stake_game_won" = "{from} won {amount}"; "lng_action_stake_game_won_you" = "You won {amount}"; "lng_action_stake_game_lost" = "{from} lost {amount}"; "lng_action_stake_game_lost_you" = "You lost {amount}"; "lng_action_change_creator" = "{from} made {user} the new main admin of the group."; "lng_action_new_creator_pending" = "{user} will become the new main admin in 7 days if {from} does not return."; "lng_action_managed_bot_created" = "{from} created a bot {bot}."; "lng_create_bot_title" = "Create Bot"; "lng_create_bot_subtitle" = "{bot} would like to create and manage a chatbot on your behalf."; "lng_create_bot_name_placeholder" = "Bot Name"; "lng_create_bot_username_placeholder" = "Bot Username"; "lng_create_bot_username_available" = "{username} is available."; "lng_create_bot_username_link" = "Link: {link}"; "lng_create_bot_username_taken" = "This username is already taken."; "lng_create_bot_username_bad_symbols" = "Username can only contain a-z, 0-9, and underscores."; "lng_create_bot_username_too_short" = "Username must be at least 5 characters."; "lng_create_bot_button" = "Create"; "lng_managed_bot_label" = "{icon} Created and managed by {bot}."; "lng_managed_bot_ready" = "**{name}** is ready!\n\nClick **Start** below to test your new chatbot. Its behavior is defined by **{parent}**."; "lng_managed_bot_created_title" = "{name} created!"; "lng_managed_bot_created_text" = "{parent_name} will manage this bot for you."; "lng_managed_bot_edit_photo" = "You can edit your bot's profile picture {link}"; "lng_managed_bot_edit_photo_link" = "here {arrow}"; "lng_managed_bot_set_photo" = "Set Profile Photo"; "lng_create_bot_no_manage" = "{bot} doesn't have Bot Management Mode enabled."; "lng_bots_create_limit#one" = "Subscribe to {link} to create up to {premium_count} bots, or delete one of your **{count}** bot via {bot}."; "lng_bots_create_limit#other" = "Subscribe to {link} to create up to {premium_count} bots, or delete one of your **{count}** bots via {bot}."; "lng_bots_create_limit_link" = "Premium"; "lng_bots_create_limit_final#one" = "You can create up to **{count}** bot. Delete your current ones via {bot}."; "lng_bots_create_limit_final#other" = "You can create up to **{count}** bots. Delete your current ones via {bot}."; "lng_stake_game_title" = "Emoji Stake"; "lng_stake_game_beta" = "Beta"; "lng_stake_game_about" = "A limited play-test of the upcoming emoji mini-game platform for a small group of users."; "lng_stake_game_results" = "Results and Returns"; "lng_stake_game_resets" = "A streak resets after 3 {emoji} or a stake change."; "lng_stake_game_your" = "Your stake"; "lng_stake_game_save_and_roll" = "Save and Roll"; "lng_you_joined_group" = "You joined this group"; "lng_similar_channels_title" = "Similar channels"; "lng_similar_channels_view_all" = "View all"; "lng_similar_channels_more" = "More Channels"; "lng_similar_channels_premium_all#one" = "Subscribe to {link} to unlock up to **{count}** similar channel."; "lng_similar_channels_premium_all#other" = "Subscribe to {link} to unlock up to **{count}** similar channels."; "lng_similar_channels_premium_all_link" = "Telegram Premium"; "lng_similar_channels_show_more" = "Show more channels"; "lng_similar_bots_title" = "Similar bots"; "lng_similar_bots_premium_all#one" = "Subscribe to {link} to unlock up to **{count}** similar bot."; "lng_similar_bots_premium_all#other" = "Subscribe to {link} to unlock up to **{count}** similar bots."; "lng_similar_bots_show_more" = "Show more bots"; "lng_peer_gifts_title" = "Gifts"; "lng_peer_gifts_about" = "These gifts were sent to {user} by other users."; "lng_peer_gifts_about_mine" = "These gifts were sent to you by other users. Click on a gift to convert it to Stars or change its privacy settings."; "lng_peer_gifts_empty_search" = "No matching gifts"; "lng_peer_gifts_view_all" = "View All Gifts"; "lng_peer_gifts_notify" = "Notify About New Gifts"; "lng_peer_gifts_notify_enabled" = "You will receive a message from Telegram when your channel receives a gift."; "lng_peer_gifts_filter_by_value" = "Sort by Value"; "lng_peer_gifts_filter_by_date" = "Sort by Date"; "lng_peer_gifts_filter_unlimited" = "Unlimited"; "lng_peer_gifts_filter_upgradable" = "Upgradeable"; "lng_peer_gifts_filter_limited" = "Limited"; "lng_peer_gifts_filter_unique" = "Unique"; "lng_peer_gifts_filter_saved" = "Displayed"; "lng_peer_gifts_filter_unsaved" = "Hidden"; "lng_premium_gift_duration_days#one" = "for {count} day"; "lng_premium_gift_duration_days#other" = "for {count} days"; "lng_premium_gift_duration_months#one" = "for {count} month"; "lng_premium_gift_duration_months#other" = "for {count} months"; "lng_premium_gift_duration_years#one" = "for {count} year"; "lng_premium_gift_duration_years#other" = "for {count} years"; "lng_ttl_photo_received" = "{from} sent you a self-destructing photo. Please view it on your mobile."; "lng_ttl_photo_sent" = "You sent a self-destructing photo."; "lng_ttl_photo_expired" = "Expired photo"; "lng_ttl_video_received" = "{from} sent you a self-destructing video. Please view it on your mobile."; "lng_ttl_video_sent" = "You sent a self-destructing video."; "lng_ttl_video_expired" = "Expired video"; "lng_ttl_voice_sent" = "You sent a self-destructing voice message."; "lng_ttl_voice_expired" = "Voice message expired"; "lng_ttl_round_sent" = "You sent a self-destructing video message."; "lng_ttl_round_expired" = "Round message expired"; "lng_ttl_voice_tooltip_in" = "This voice message can only be played once."; "lng_ttl_voice_tooltip_out" = "This message will disappear after **{user}** plays it once."; "lng_ttl_voice_close_in" = "Delete and close"; "lng_ttl_round_tooltip_in" = "This video message can only be played once."; "lng_ttl_round_tooltip_out" = "This message will disappear after **{user}** plays it once."; "lng_profile_add_more_after_create" = "You will be able to add more members after you create the group."; "lng_profile_camera_title" = "Capture yourself"; "lng_channel_not_accessible" = "Sorry, this channel is not accessible."; "lng_group_not_accessible" = "Sorry, this group is not accessible."; "lng_group_full" = "Sorry, this group is full."; "lng_channels_too_much_public_revoke_confirm_group" = "Are you sure you want to revoke the link {link}?\n\nThe group «{group}» will become private."; "lng_channels_too_much_public_revoke_confirm_channel" = "Are you sure you want to revoke the link {link}?\n\nThe channel «{group}» will become private."; "lng_channels_too_much_public_revoke" = "Revoke"; "lng_channels_too_much_public_other" = "Sorry, the target user has too many public groups or channels already. Please ask them to make one of their existing groups or channels private first."; "lng_channels_too_much_located_other" = "Sorry, the target user has too many location-based groups already. Please ask them to delete or transfer one of their existing ones first."; "lng_group_invite_bad_link" = "This invite link is invalid or has expired."; "lng_group_invite_members#one" = "{count} member, among them:"; "lng_group_invite_members#other" = "{count} members, among them:"; "lng_channel_invite_private" = "This channel is private.\nPlease join it to continue viewing its content."; "lng_channel_invite_subscription_button" = "Subscribe"; "lng_channel_invite_subscription_title" = "Subscribe to the Channel"; "lng_channel_invite_subscription_about" = "Do you want to subscribe for {channel} for {price} per month?"; "lng_channel_invite_subscription_terms" = "By subscribing you agree to the {link}."; "lng_group_invite_create" = "Create an invite link"; "lng_group_invite_about_new" = "Your previous link will be deactivated and we'll generate a new invite link for you."; "lng_group_invite_copied" = "Invite link copied to clipboard."; "lng_group_invite_no_room" = "Unable to join this group because it has too many members."; "lng_group_invite_copy" = "Copy Link"; "lng_group_invite_share" = "Share Link"; "lng_group_invite_reactivate" = "Reactivate Link"; "lng_group_invite_delete" = "Delete Link"; "lng_group_invite_no_joined" = "No one joined yet"; "lng_group_invite_joined#one" = "{count} joined"; "lng_group_invite_joined#other" = "{count} joined"; "lng_group_invite_joined_via_filter" = "joined via a folder invite link"; "lng_group_invite_remaining#one" = "{count} remaining"; "lng_group_invite_remaining#other" = "{count} remaining"; "lng_group_invite_requested#one" = "{count} request"; "lng_group_invite_requested#other" = "{count} requests"; "lng_group_invite_requested_full#one" = "{count} join request"; "lng_group_invite_requested_full#other" = "{count} join requests"; "lng_group_invite_can_join#one" = "{count} can join"; "lng_group_invite_can_join#other" = "{count} can join"; "lng_group_invite_days_left#one" = "{count} day left"; "lng_group_invite_days_left#other" = "{count} days left"; "lng_group_invite_about_permanent_group" = "Anyone who has Telegram installed will be able to join your group by following this link."; "lng_group_invite_about_permanent_channel" = "Anyone who has Telegram installed will be able to join your channel by following this link."; "lng_group_invite_title" = "Invite links"; "lng_group_invite_add" = "Create a New Link"; "lng_group_invite_add_about" = "You can generate invite links that expire after they are used."; "lng_group_invite_expires_at" = "This link expires {when}."; "lng_group_invite_created_by" = "Link created by"; "lng_group_invite_links_count#one" = "{count} link"; "lng_group_invite_links_count#other" = "{count} links"; "lng_group_invite_context_copy" = "Copy"; "lng_group_invite_context_share" = "Share"; "lng_group_invite_context_edit" = "Edit"; "lng_group_invite_context_qr" = "Get QR Code"; "lng_group_invite_context_revoke" = "Revoke"; "lng_group_invite_context_delete" = "Delete"; "lng_group_invite_context_delete_all" = "Delete all"; "lng_group_invite_delete_sure" = "Are you sure you want to delete this revoked link?"; "lng_group_invite_delete_all_sure" = "Are you sure you want to delete all revoked links? This action cannot be undone."; "lng_group_invite_revoked_title" = "Revoked links"; "lng_group_invite_revoke_about" = "Are you sure you want to revoke this invite link?"; "lng_group_invite_link_expired" = "Expired"; "lng_group_invite_edit_title" = "Edit Link"; "lng_group_invite_new_title" = "New Link"; "lng_group_invite_label_header" = "Link Name (optional)"; "lng_group_invite_label_about" = "Only admins will see this name."; "lng_group_invite_expire_title" = "Limit by time period"; "lng_group_invite_expire_about" = "You can make the link expire after a certain time."; "lng_group_invite_expire_never" = "No limit"; "lng_group_invite_expire_custom" = "Custom"; "lng_group_invite_usage_title" = "Limit by number of users"; "lng_group_invite_usage_about" = "You can make the link work only for a certain number of users."; "lng_group_invite_expire_after" = "Expire after"; "lng_group_invite_custom_limit" = "Enter custom limit"; "lng_group_invite_usage_any" = "No limit"; "lng_group_invite_usage_custom" = "Custom"; "lng_group_invite_other_title" = "Links created by other admins"; "lng_group_invite_other_count#one" = "{count} invite link"; "lng_group_invite_other_count#other" = "{count} invite links"; "lng_group_invite_other_list" = "Links created by this admin"; "lng_group_invite_expired_about" = "The time limit for this link has expired."; "lng_group_invite_used_about" = "This link reached its usage limit."; "lng_group_invite_can_join_via_link#one" = "{count} person can join via this link."; "lng_group_invite_can_join_via_link#other" = "{count} people can join via this link."; "lng_group_invite_qr_title" = "Invite by QR Code"; "lng_group_invite_qr_about" = "Everyone on Telegram can scan this code to join your group."; "lng_group_invite_qr_copied" = "QR Code copied to clipboard."; "lng_group_invite_request_approve" = "Request admin approval"; "lng_group_invite_about_approve" = "Turn this on if you want users to join only after they are approved by an admin."; "lng_group_invite_about_no_approve" = "Turn this on if you want users to join only after they are approved by an admin."; "lng_group_invite_about_approve_channel" = "Turn this on if you want users to join only after they are approved by an admin."; "lng_group_invite_about_no_approve_channel" = "Turn this on if you want users to join only after they are approved by an admin."; "lng_group_invite_subscription" = "Require Monthly Fee"; "lng_group_invite_subscription_ph" = "Stars Amount per month"; "lng_group_invite_subscription_price" = "~{cost} / month"; "lng_group_invite_subscription_toast" = "To change the subscription fee, create a new invite link with a different price."; "lng_group_invite_subscription_about" = "Charge a subscription fee from people who join your channel via this link. {link}"; "lng_group_invite_subscription_about_link" = "Learn more {emoji}"; "lng_group_invite_subscription_about_url" = "https://telegram.org/tos/stars"; "lng_group_invite_subscription_info_subtitle" = "Subscription fee"; "lng_group_invite_subscription_info_title" = "{emoji} {price} / month {multiplier} {total}"; "lng_group_invite_subscription_info_title_none" = "{emoji} {price} / month"; "lng_group_invite_subscription_info_about" = "you get approximately {total} monthly"; "lng_group_invite_joined_right" = "per month"; "lng_group_invite_joined_status" = "joined {date}"; "lng_group_invite_joined_row_subscriber" = "Subscriber"; "lng_group_invite_joined_row_date" = "Subscribed"; "lng_group_request_to_join" = "Request to Join"; "lng_group_request_about" = "This group accepts new members only after they are approved by its admins."; "lng_group_request_about_channel" = "This channel accepts new subscribers only after they are approved by its admins."; "lng_group_request_sent" = "You will be added to the group once an admin approves your request."; "lng_group_request_sent_channel" = "You will be added to the channel once its admins approve your request."; "lng_group_requests_pending#one" = "{count} join request"; "lng_group_requests_pending#other" = "{count} join requests"; "lng_group_requests_pending_user" = "{user} requested to join"; "lng_group_requests_status_today" = "requested to join today at {time}"; "lng_group_requests_status_yesterday" = "requested to join yesterday at {time}"; "lng_group_requests_status_date_time" = "requested to join {date} at {time}"; "lng_group_requests_add" = "Add to Group"; "lng_group_requests_add_channel" = "Add to Channel"; "lng_group_requests_dismiss" = "Dismiss"; "lng_group_requests_was_added" = "{user} has been added to the group."; "lng_group_requests_was_added_channel" = "{user} has been added to the channel."; "lng_group_requests_none" = "There are no pending join requests."; "lng_group_requests_none_channel" = "There are no pending join requests."; "lng_channel_public_link_copied" = "Link copied to clipboard."; "lng_context_about_private_link" = "This link will only work for members of this chat."; "lng_public_post_private_hint_ctrl" = "Use Ctrl+Click to copy a non-public link."; "lng_public_post_private_hint_cmd" = "Use Cmd+Click to copy a non-public link."; "lng_forwarded" = "Forwarded from {user}"; "lng_forwarded_story" = "Story from {user}"; "lng_forwarded_story_expired" = "This story has expired."; "lng_forwarded_date" = "Original: {date}"; "lng_forwarded_forwarded_date" = "Forwarded date: {date}"; "lng_forwarded_channel" = "Forwarded from {channel}"; "lng_forwarded_psa_default" = "Forwarded from {channel}"; "lng_forwarded_via" = "Forwarded from {user} via {inline_bot}"; "lng_forwarded_channel_via" = "Forwarded from {channel} via {inline_bot}"; "lng_forwarded_signed" = "{channel} ({user})"; "lng_forwarded_hidden" = "The account was hidden by the user."; "lng_forwarded_imported" = "This message was imported from another app. It may not be real."; "lng_signed_author" = "Author: {user}"; "lng_sponsored_message_title" = "Ad"; "lng_sponsored_message_revenue_button" = "what's this?"; "lng_recommended_message_title" = "Recommended"; "lng_edited" = "edited"; "lng_commented" = "commented"; "lng_approximate" = "appx."; "lng_repeated_daily" = "daily"; "lng_repeated_weekly" = "weekly"; "lng_repeated_biweekly" = "biweekly"; "lng_repeated_monthly" = "monthly"; "lng_repeated_every_month#one" = "{count}-monthly"; "lng_repeated_every_month#other" = "{count}-monthly"; "lng_repeated_yearly" = "yearly"; "lng_edited_date" = "Edited: {date}"; "lng_sent_date" = "Sent: {date}"; "lng_approximate_about" = "Estimated date of video publishing."; "lng_views_tooltip#one" = "Views: {count}"; "lng_views_tooltip#other" = "Views: {count}"; "lng_forwards_tooltip#one" = "Shares: {count}"; "lng_forwards_tooltip#other" = "Shares: {count}"; "lng_imported" = "imported"; "lng_admin_badge" = "admin"; "lng_owner_badge" = "owner"; "lng_channel_badge" = "channel"; "lng_topic_author_badge" = "Topic Creator"; "lng_fast_reply" = "Reply"; "lng_fast_share_tooltip" = "Right-click to select a Recent Contact."; "lng_cancel_edit_post_sure" = "Cancel editing?"; "lng_cancel_edit_post_yes" = "Yes"; "lng_cancel_edit_post_no" = "No"; "lng_bot_share_location_unavailable" = "Sorry, location sharing is currently unavailable in Telegram Desktop."; "lng_bot_share_phone" = "Do you want to share your phone number with this bot?"; "lng_bot_share_phone_confirm" = "Share"; "lng_bot_allow_write_title" = "Allow messaging"; "lng_bot_allow_write" = "Do you want to allow this bot to send you messages?"; "lng_bot_allow_write_confirm" = "Allow"; "lng_bot_new_chat" = "New Chat"; "lng_bot_new_thread_title" = "New Thread"; "lng_bot_new_thread_about" = "Type any message to create a new thread."; "lng_bot_show_threads_list" = "Show Threads List"; "lng_bot_off_thread_ph" = "Off-thread message"; "lng_attach_failed" = "Failed"; "lng_attach_file" = "File"; "lng_attach_photo" = "Photo"; "lng_attach_camera" = "Camera"; "lng_attach_document" = "Document"; "lng_attach_photo_or_video" = "Photo or video"; "lng_attach_profile_emoji" = "Use an Emoji"; "lng_media_open_with" = "Open With"; "lng_media_download" = "Download"; "lng_media_cancel" = "Cancel"; "lng_media_video" = "Video"; "lng_media_audio" = "Voice message"; "lng_media_round" = "Video message"; "lng_media_auto_settings" = "Automatic media download"; "lng_media_auto_in_private" = "In private chats"; "lng_media_auto_in_groups" = "In groups"; "lng_media_auto_in_channels" = "In channels"; "lng_media_auto_title" = "Automatically download"; "lng_media_auto_play" = "Autoplay"; "lng_media_photo_title" = "Photos"; "lng_media_video_title" = "Videos"; "lng_media_video_messages_title" = "Round video messages"; "lng_media_file_title" = "Files"; "lng_media_animation_title" = "GIFs"; "lng_media_size_limit" = "Limit by size"; "lng_media_size_up_to" = "up to {size}"; "lng_media_chat_background" = "Chat Wallpaper"; "lng_media_color_theme" = "Color theme"; "lng_emoji_category1" = "Emoji & People"; "lng_emoji_category2" = "Nature"; "lng_emoji_category3" = "Food & Drink"; "lng_emoji_category4" = "Activity"; "lng_emoji_category5" = "Travel & Places"; "lng_emoji_category6" = "Objects"; "lng_emoji_category7" = "Symbols & Flags"; "lng_emoji_manage_sets" = "Choose emoji set"; "lng_emoji_set_ready" = "Downloaded"; "lng_emoji_set_active" = "Current set"; "lng_emoji_set_download" = "Download {size}"; "lng_emoji_set_loading" = "{percent}, {progress}"; "lng_emoji_color_all" = "Choose color for all emoji"; "lng_emoji_copy" = "Copy emoji"; "lng_emoji_view_pack" = "View pack"; "lng_emoji_remove_recent" = "Remove from Recent"; "lng_emoji_reset_recent" = "Reset recents"; "lng_emoji_reset_recent_sure" = "Do you want to reset recent emoji?"; "lng_emoji_reset_recent_button" = "Reset"; "lng_recent_stickers" = "Recently used"; "lng_faved_stickers_add" = "Add to Favorites"; "lng_faved_stickers_remove" = "Remove from Favorites"; "lng_recent_stickers_remove" = "Remove from Recent"; "lng_group_stickers" = "Group stickers"; "lng_group_stickers_description" = "You can choose a sticker set which will be available for every member while in the group chat."; "lng_group_stickers_add" = "Choose sticker set"; "lng_group_emoji" = "Select Emoji Pack"; "lng_group_emoji_description" = "Choose an emoji pack that will be available to all members within the group."; "lng_collectible_emoji" = "Collectibles"; "lng_premium" = "Premium"; "lng_premium_free" = "Free"; "lng_premium_more_about" = "About Telegram Premium"; "lng_premium_unlock_reactions" = "Unlock Premium Reactions"; "lng_premium_unlock_stickers" = "Unlock Premium Stickers"; "lng_premium_unlock_emoji" = "Unlock Animated Emoji"; "lng_premium_unlock_status" = "Unlock Emoji Status"; "lng_premium_subscribe_months_24" = "2-Year"; "lng_premium_subscribe_months_12" = "Annual"; "lng_premium_subscribe_months_6" = "Semiannual"; "lng_premium_subscribe_months_1" = "Monthly"; "lng_premium_subscribe_total" = "{cost} per year"; "lng_premium_subscribe_button" = "Subscribe for {cost} per month"; "lng_premium_emoji_status_title" = "{user} set this emoji from {link} as their current status."; "lng_premium_emoji_status_title_colored" = "{user} set this emoji as their current status."; "lng_premium_emoji_status_about" = "Emoji status is a premium feature. Other features included in **Telegram Premium**:"; "lng_premium_emoji_status_button" = "Unlock Emoji Status"; "lng_premium_summary_user_title" = "{user} is a subscriber of Telegram Premium."; "lng_premium_summary_user_about" = "Owners of Telegram Premium accounts have exclusive access to multiple additional features."; "lng_premium_summary_title" = "Telegram Premium"; "lng_premium_summary_top_about" = "Go **beyond the limits** and **unlock dozens of exclusive** features by subscribing to **Telegram Premium**."; "lng_premium_summary_title_subscribed" = "You are all set!"; "lng_premium_summary_subtitle_gift#one" = "{user} has gifted you a {count}-month subscription to Telegram Premium."; "lng_premium_summary_subtitle_gift#other" = "{user} has gifted you a {count}-months subscription to Telegram Premium."; "lng_premium_summary_subtitle_gift_days#one" = "{user} has gifted you a {count}-day subscription to Telegram Premium."; "lng_premium_summary_subtitle_gift_days#other" = "{user} has gifted you a {count}-days subscription to Telegram Premium."; "lng_premium_summary_subtitle_gift_me#one" = "You gifted {user} a {count}-month subscription to Telegram Premium."; "lng_premium_summary_subtitle_gift_me#other" = "You gifted {user} a {count}-months subscription to Telegram Premium."; "lng_premium_summary_subtitle_gift_days_me#one" = "You gifted {user} a {count}-month subscription to Telegram Premium."; "lng_premium_summary_subtitle_gift_days_me#other" = "You gifted {user} a {count}-months subscription to Telegram Premium."; "lng_premium_summary_subtitle_wallpapers" = "Wallpapers for Both Sides"; "lng_premium_summary_about_wallpapers" = "Set custom wallpapers for you and your chat partner."; "lng_premium_summary_subtitle_stories" = "Stories"; "lng_premium_summary_about_stories" = "Unlimited posting, priority order, stealth mode, permanent view history and more."; "lng_premium_summary_subtitle_double_limits" = "Doubled Limits"; "lng_premium_summary_about_double_limits" = "Up to 1000 channels, 30 folders, 10 pins, 20 public links, 4 accounts and more."; "lng_premium_summary_subtitle_more_upload" = "Unlimited Cloud Storage"; "lng_premium_summary_about_more_upload" = "4 GB per each document, unlimited storage for your chats and media overall."; "lng_premium_summary_subtitle_faster_download" = "Faster Download Speed"; "lng_premium_summary_about_faster_download" = "No more limits on the speed with which media and documents are downloaded."; "lng_premium_summary_subtitle_voice_to_text" = "Voice-to-Text Conversion"; "lng_premium_summary_about_voice_to_text" = "Ability to read the transcript of any incoming voice message."; "lng_premium_summary_subtitle_no_ads" = "No Ads"; "lng_premium_summary_about_no_ads" = "No more ads in public channels where Telegram sometimes shows ads."; "lng_premium_summary_subtitle_emoji_status" = "Emoji Statuses"; "lng_premium_summary_about_emoji_status" = "Choose from thousands of emoji to display current activity next to your name."; "lng_premium_summary_subtitle_infinite_reactions" = "Infinite Reactions"; "lng_premium_summary_about_infinite_reactions" = "React with thousands of emoji — with multiple reactions per message."; "lng_premium_summary_subtitle_tags_for_messages" = "Tags for Messages"; "lng_premium_summary_about_tags_for_messages" = "Organize your Saved Messages with tags for quicker access."; "lng_premium_summary_subtitle_last_seen" = "Last Seen Times"; "lng_premium_summary_about_last_seen" = "View the last seen and read times of others even if you hide yours."; "lng_premium_summary_subtitle_message_privacy" = "Message Privacy"; "lng_premium_summary_about_message_privacy" = "Restrict people you don't know from sending you messages."; "lng_premium_summary_subtitle_premium_stickers" = "Premium Stickers"; "lng_premium_summary_about_premium_stickers" = "Exclusive enlarged stickers featuring additional effects, updated monthly."; "lng_premium_summary_subtitle_animated_emoji" = "Animated Emoji"; "lng_premium_summary_about_animated_emoji" = "Include animated emoji from different packs in any message you send."; "lng_premium_summary_subtitle_advanced_chat_management" = "Advanced Chat Management"; "lng_premium_summary_about_advanced_chat_management" = "Tools to set the default folder, auto-archive and hide new chats from non-contacts."; "lng_premium_summary_subtitle_profile_badge" = "Profile Badge"; "lng_premium_summary_about_profile_badge" = "An exclusive badge next to your name showing that you subscribe to Telegram Premium."; "lng_premium_summary_subtitle_animated_userpics" = "Animated Profile Pictures"; "lng_premium_summary_about_animated_userpics" = "Video avatars animated in chat lists and chats to allow for additional self-expression."; "lng_premium_summary_subtitle_translation" = "Real-Time Translation"; "lng_premium_summary_about_translation" = "Real-time translation of channels and chats into other languages."; "lng_premium_summary_subtitle_business" = "Telegram Business"; "lng_premium_summary_about_business" = "Upgrade your account with business features such as location, opening hours and quick replies."; "lng_premium_summary_subtitle_effects" = "Message Effects"; "lng_premium_summary_about_effects" = "Add over 500 animated effects to private messages."; "lng_premium_summary_subtitle_filter_tags" = "Tag Your Chats"; "lng_premium_summary_about_filter_tags" = "Display folder names for each chat in the chat list."; "lng_premium_summary_subtitle_todo_lists" = "Checklists"; "lng_premium_summary_about_todo_lists" = "Plan, assign, and complete tasks - seamlessly and efficiently."; "lng_premium_summary_subtitle_peer_colors" = "Name and Profile Colors"; "lng_premium_summary_about_peer_colors" = "Choose a color and logo for your profile and replies to your messages."; "lng_premium_summary_subtitle_gifts" = "Telegram Gifts"; "lng_premium_summary_about_gifts" = "Gifts are collectible items you can trade or showcase on your profile."; "lng_premium_summary_subtitle_no_forwards" = "Disable Sharing"; "lng_premium_summary_about_no_forwards" = "Restrict forwarding, copying, and saving content from your private chats."; "lng_premium_summary_subtitle_ai_compose" = "AI Tools"; "lng_premium_summary_about_ai_compose" = "Transform your messages and entire chats in your preferred style and language."; "lng_premium_summary_bottom_subtitle" = "About Telegram Premium"; "lng_premium_summary_bottom_about" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone."; "lng_premium_summary_button" = "Subscribe for {cost} per month"; "lng_premium_summary_new_badge" = "NEW"; "lng_soon_badge" = "Soon"; "lng_premium_success" = "You've successfully subscribed to Telegram Premium!"; "lng_premium_unavailable" = "This feature requires subscription to **Telegram Premium**.\n\nUnfortunately, **Telegram Premium** is not available in your region."; // Upgraded Stories. "lng_premium_stories_subtitle_order" = "Priority Order"; "lng_premium_stories_about_order" = "Get more views as your stories are always displayed first."; "lng_premium_stories_subtitle_stealth" = "Stealth Mode"; "lng_premium_stories_about_stealth" = "Hide the fact that you viewed other people's stories."; "lng_premium_stories_subtitle_views" = "Permanent View History"; "lng_premium_stories_about_views" = "Check who opens your stories — even after they expire."; "lng_premium_stories_subtitle_expiration" = "Expiration Options*"; "lng_premium_stories_about_expiration" = "Set custom durations like 6 or 48 hours for your stories."; "lng_premium_stories_subtitle_download" = "Download Stories"; "lng_premium_stories_about_download" = "Save other people's stories that are not protected."; "lng_premium_stories_subtitle_caption" = "Longer Captions*"; "lng_premium_stories_about_caption" = "Add 10x longer captions to your stories – up to 2048 characters."; "lng_premium_stories_subtitle_links" = "Links and Formatting*"; "lng_premium_stories_about_links" = "Add links and formatting to your story captions."; "lng_premium_stories_about_mobile" = "* Available when posting stories from Telegram apps for iOS and Android."; // Doubled Limits. "lng_premium_double_limits_subtitle_channels" = "Groups and Channels"; "lng_premium_double_limits_about_channels#one" = "Join up to {count} channel or large group"; "lng_premium_double_limits_about_channels#other" = "Join up to {count} channels and large groups"; "lng_premium_double_limits_subtitle_pins" = "Pinned Chats"; "lng_premium_double_limits_about_pins#one" = "Pin up to {count} chat in your main chat list"; "lng_premium_double_limits_about_pins#other" = "Pin up to {count} chats in your main chat list"; "lng_premium_double_limits_subtitle_links" = "Public Links"; "lng_premium_double_limits_about_links#one" = "Reserve up to {count} t.me/username link"; "lng_premium_double_limits_about_links#other" = "Reserve up to {count} t.me/username links"; "lng_premium_double_limits_subtitle_gifs" = "Saved GIFs"; "lng_premium_double_limits_about_gifs#one" = "Save up to {count} GIF in your Favorite GIFs"; "lng_premium_double_limits_about_gifs#other" = "Save up to {count} GIFs in your Favorite GIFs"; "lng_premium_double_limits_subtitle_stickers" = "Favorite Stickers"; "lng_premium_double_limits_about_stickers#one" = "Save up to {count} sticker in your Favorite stickers"; "lng_premium_double_limits_about_stickers#other" = "Save up to {count} stickers in your Favorite stickers"; "lng_premium_double_limits_subtitle_bio" = "Bio"; "lng_premium_double_limits_about_bio" = "Use more characters and add links in your bio"; "lng_premium_double_limits_subtitle_captions" = "Captions"; "lng_premium_double_limits_about_captions" = "Use longer descriptions for your photos and videos"; "lng_premium_double_limits_subtitle_folders" = "Folders"; "lng_premium_double_limits_about_folders#one" = "Organize your chats into {count} folder"; "lng_premium_double_limits_about_folders#other" = "Organize your chats into {count} folders"; "lng_premium_double_limits_subtitle_folder_chats" = "Chats per Folder"; "lng_premium_double_limits_about_folder_chats#one" = "Add up to {count} chat into each of your folders"; "lng_premium_double_limits_about_folder_chats#other" = "Add up to {count} chats into each of your folders"; "lng_premium_double_limits_subtitle_accounts" = "Connected Accounts"; "lng_premium_double_limits_about_accounts#one" = "Connect {count} account with different mobile numbers"; "lng_premium_double_limits_about_accounts#other" = "Connect {count} accounts with different mobile numbers"; "lng_premium_double_limits_subtitle_similar_channels" = "Similar Channel"; "lng_premium_double_limits_about_similar_channels#one" = "View up to {count} similar channel"; "lng_premium_double_limits_about_similar_channels#other" = "View up to {count} similar channels"; // "lng_premium_gift_title" = "Gift Telegram Premium"; "lng_premium_gift_about" = "Give **{user}** access to exclusive features with **Telegram Premium**."; "lng_premium_gift_button" = "Gift Subscription for {cost}"; "lng_premium_gift_per" = "{cost} / month"; "lng_premium_gift_terms" = "You can review the list of features and more details about Telegram Premium {link}."; "lng_premium_gift_terms_link" = "here"; "lng_premium_gifts_about_user1" = "Give **{user}** access to exclusive features."; "lng_premium_gifts_about_user2" = "Give **{user}** and **{second_user}** access to exclusive features."; "lng_premium_gifts_about_user3" = "Give **{user}**, **{second_user}** and **{name}** access to exclusive features."; "lng_premium_gifts_about_user_more#one" = "Give **{user}**, **{second_user}**, **{name}** and **{count}** more friend access to exclusive features."; "lng_premium_gifts_about_user_more#other" = "Give **{user}**, **{second_user}**, **{name}** and **{count}** more friends access to exclusive features."; "lng_premium_gifts_about_reward#one" = "You will receive {emoji}**{count}** boost."; "lng_premium_gifts_about_reward#other" = "You will receive {emoji}**{count}** boosts."; "lng_premium_gifts_about_paid_title" = "Gifts Sent!"; "lng_premium_gifts_about_paid1" = "**{user}** has been notified about the gifts you purchased."; "lng_premium_gifts_about_paid2" = "**{user}** and **{second_user}** have been notified about the gifts you purchased."; "lng_premium_gifts_about_paid3" = "**{user}**, **{second_user}** and **{name}** have been notified about the gifts you purchased."; "lng_premium_gifts_about_paid_more#one" = "**{user}**, **{second_user}**, **{name}** and **{count}** other have been notified about the gifts you purchased."; "lng_premium_gifts_about_paid_more#other" = "**{user}**, **{second_user}**, **{name}** and **{count}** others have been notified about the gifts you purchased."; "lng_premium_gifts_about_paid_below#one" = "They now have access to additional features."; "lng_premium_gifts_about_paid_below#other" = "They now have access to additional features."; "lng_premium_gifts_summary_subtitle" = "What's Included"; "lng_premium_gifts_terms" = "By gifting Telegram Premium, you agree to the Telegram {link} and {policy}."; "lng_premium_gifts_terms_policy" = "Privacy Policy"; "lng_business_title" = "Telegram Business"; "lng_business_about" = "Turn your account to a business page with these additional features."; "lng_business_unlocked" = "You have now unlocked these additional business features."; "lng_business_subtitle_location" = "Location"; "lng_business_about_location" = "Display the location of your business on your account."; "lng_business_subtitle_opening_hours" = "Opening Hours"; "lng_business_about_opening_hours" = "Show to your customers when you are open for business."; "lng_business_subtitle_quick_replies" = "Quick Replies"; "lng_business_about_quick_replies" = "Set up shortcuts with rich text and media to respond to messages faster."; "lng_business_subtitle_greeting_messages" = "Greeting Messages"; "lng_business_about_greeting_messages" = "Create greetings that will be automatically sent to new customers."; "lng_business_subtitle_away_messages" = "Away Messages"; "lng_business_about_away_messages" = "Define messages that are automatically sent when you are off."; "lng_business_subtitle_chatbots" = "Chatbots"; "lng_business_about_chatbots" = "Add any third party chatbots that will process customer interactions."; "lng_business_subtitle_chat_intro" = "Custom Intro"; "lng_business_about_chat_intro" = "Customize the message people see before they start a chat with you."; "lng_business_subtitle_chat_links" = "Links to Chat"; "lng_business_about_chat_links" = "Create links that start a chat with you, suggesting the first message."; "lng_business_subtitle_sponsored" = "Ads in Channels"; "lng_business_button_sponsored" = "Do Not Hide Ads"; "lng_business_about_sponsored" = "As a Premium subscriber, you don’t see any ads on Telegram, but you can turn them on, for example, to view your own ads that you launched on the {link}"; "lng_business_about_sponsored_link" = "Telegram Ad Platform {emoji}"; "lng_business_about_sponsored_url" = "https://ads.telegram.org"; "lng_credits_summary_title" = "Telegram Stars"; "lng_credits_summary_about" = "Buy Stars to unlock content and services in miniapps on Telegram."; "lng_credits_currency_summary_title" = "TON Balance"; "lng_credits_currency_summary_about" = "Offer TON to submit post suggestions to channels on Telegram."; "lng_credits_currency_summary_subtitle" = "You can withdraw your TON using Fragment."; "lng_credits_currency_summary_in_button" = "Top-up via Fragment"; "lng_credits_currency_summary_in_subtitle" = "You can top-up your TON balance via Fragment."; "lng_credits_summary_options_subtitle" = "Choose package"; "lng_credits_summary_options_credits#one" = "{count} Star"; "lng_credits_summary_options_credits#other" = "{count} Stars"; "lng_credits_summary_options_more" = "More Options"; "lng_credits_summary_options_about" = "By proceeding and purchasing Stars, you agree with the {link}."; "lng_credits_summary_options_about_link" = "Terms and Conditions"; "lng_credits_summary_options_about_url" = "https://telegram.org/tos/stars"; "lng_credits_summary_earn_title" = "Earn Stars"; "lng_credits_summary_earn_about" = "Distribute links to mini apps and earn a share of their revenue in Stars."; "lng_credits_summary_history_tab_full" = "All Transactions"; "lng_credits_summary_history_tab_in" = "Incoming"; "lng_credits_summary_history_tab_out" = "Outgoing"; "lng_credits_summary_history_entry_inner_in" = "In-App Purchase"; "lng_credits_summary_balance" = "Balance"; "lng_credits_commission" = "{amount} commission"; "lng_credits_paid_messages_fee_live_reaction" = "Fee for Live Story Reaction"; "lng_credits_paid_messages_fee#one" = "Fee for {count} Message"; "lng_credits_paid_messages_fee#other" = "Fee for {count} Messages"; "lng_credits_paid_messages_fee_about" = "You receive {percent} of the price that you charge for each incoming message. {link}"; "lng_credits_paid_messages_fee_about_link" = "Change Fee {emoji}"; "lng_credits_paid_messages_full" = "Full Price"; "lng_credits_premium_gift_duration" = "Duration"; "lng_credits_more_options" = "More Options"; "lng_credits_balance_me" = "your balance"; "lng_credits_balance_me_count" = "Your balance: {emoji} {amount}"; "lng_credits_buy_button" = "Top Up Balance"; "lng_credits_topup_button" = "{emoji} Top Up Balance"; "lng_credits_buy_button_short" = "Top Up"; "lng_credits_stats_button_short" = "Stats"; "lng_credits_stats_button" = "View Statistics"; "lng_credits_gift_button" = "Gift Stars to Friends"; "lng_credits_earn_button" = "Earn Stars from Mini Apps"; "lng_credits_box_out_title" = "Confirm Your Purchase"; "lng_credits_box_out_sure#one" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Star**?"; "lng_credits_box_out_sure#other" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Stars**?"; "lng_credits_box_out_media#one" = "Do you want to unlock {media} in {chat} for **{count} Star**?"; "lng_credits_box_out_media#other" = "Do you want to unlock {media} in {chat} for **{count} Stars**?"; "lng_credits_box_out_media_user#one" = "Do you want to unlock {media} from {user} for **{count} Star**?"; "lng_credits_box_out_media_user#other" = "Do you want to unlock {media} from {user} for **{count} Stars**?"; "lng_credits_box_out_subscription_bot#one" = "Do you want to subscribe to **{title}** in **{recipient}** for **{count}** star per month?"; "lng_credits_box_out_subscription_bot#other" = "Do you want to subscribe to **{title}** in **{recipient}** for **{count}** stars per month?"; "lng_credits_box_out_subscription_business#one" = "Do you want to subscribe to **{title}** from **{recipient}** for **{count}** star per month?"; "lng_credits_box_out_subscription_business#other" = "Do you want to subscribe to **{title}** from **{recipient}** for **{count}** stars per month?"; "lng_credits_box_out_subscription_confirm#one" = "Subscribe for {emoji} {count} / month"; "lng_credits_box_out_subscription_confirm#other" = "Subscribe for {emoji} {count} / month"; "lng_credits_box_out_photo" = "a photo"; "lng_credits_box_out_photos#one" = "{count} photo"; "lng_credits_box_out_photos#other" = "{count} photos"; "lng_credits_box_out_video" = "a video"; "lng_credits_box_out_videos#one" = "{count} video"; "lng_credits_box_out_videos#other" = "{count} videos"; "lng_credits_box_out_both" = "{photo} and {video}"; "lng_credits_box_out_confirm#one" = "Confirm and Pay {emoji} {count} Star"; "lng_credits_box_out_confirm#other" = "Confirm and Pay {emoji} {count} Stars"; "lng_credits_box_out_about" = "Review the {link} for Stars."; "lng_credits_box_out_about_link" = "https://telegram.org/tos/stars"; "lng_credits_media_done_title" = "Media Unlocked"; "lng_credits_media_done_text#one" = "**{count} Star** transferred to {chat}."; "lng_credits_media_done_text#other" = "**{count} Stars** transferred to {chat}."; "lng_credits_media_done_text_user#one" = "**{count} Star** transferred to {user}."; "lng_credits_media_done_text_user#other" = "**{count} Stars** transferred to {user}."; "lng_credits_summary_in_toast_title" = "Stars Acquired"; "lng_credits_summary_in_toast_about#one" = "**{count}** Star added to your balance."; "lng_credits_summary_in_toast_about#other" = "**{count}** Stars added to your balance."; "lng_credits_box_history_entry_peer" = "Recipient"; "lng_credits_box_history_entry_peer_in" = "From"; "lng_credits_box_history_entry_gift_from" = "Gift From"; "lng_credits_box_history_entry_via" = "Via"; "lng_credits_box_history_entry_play_market" = "Play Store"; "lng_credits_box_history_entry_app_store" = "App Store"; "lng_credits_box_history_entry_fragment" = "Fragment"; "lng_credits_box_history_entry_anonymous" = "Unknown User"; "lng_credits_box_history_entry_gift_name" = "Received Gift"; "lng_credits_box_history_entry_giveaway_name" = "Received Prize"; "lng_credits_box_history_entry_gift_sent" = "Sent Gift"; "lng_credits_box_history_entry_gift_converted" = "Converted Gift"; "lng_credits_box_history_entry_gift_transfer" = "Gift Transfer"; "lng_credits_box_history_entry_gift_unavailable" = "Unavailable"; "lng_credits_box_history_entry_gift_released" = "released by {name}"; "lng_credits_box_history_entry_gift_sold_out" = "This gift has sold out"; "lng_credits_box_history_entry_gift_out_about" = "With Stars, **{user}** will be able to unlock content and services on Telegram.\n{link}"; "lng_credits_box_history_entry_gift_in_about" = "Use Stars to unlock content and services on Telegram. {link}"; "lng_credits_box_history_entry_gift_about_link" = "See Examples {emoji}"; "lng_credits_box_history_entry_gift_examples" = "Examples"; "lng_credits_box_history_entry_ads" = "Ads Platform"; "lng_credits_box_history_entry_premium_bot" = "Stars Top-Up"; "lng_credits_box_history_entry_currency_in" = "TON Top-Up"; "lng_credits_box_history_entry_posts_search" = "Posts Search"; "lng_credits_box_history_entry_api" = "Paid Broadcast"; "lng_credits_box_history_entry_floodskip_about#one" = "{count} Message"; "lng_credits_box_history_entry_floodskip_about#other" = "{count} Messages"; "lng_credits_box_history_entry_floodskip_row" = "Messages"; "lng_credits_box_history_entry_via_premium_bot" = "Premium Bot"; "lng_credits_box_history_entry_id" = "Transaction ID"; "lng_credits_box_history_entry_id_copied" = "Transaction ID copied to clipboard."; "lng_credits_box_history_entry_reason_star_ref" = "Affiliate Program"; "lng_credits_box_history_entry_affiliate" = "Affiliate"; "lng_credits_box_history_entry_miniapp" = "Mini App"; "lng_credits_box_history_entry_referred" = "Referred User"; "lng_credits_box_history_entry_success_date" = "Transaction date"; "lng_credits_box_history_entry_success_url" = "Transaction link"; "lng_credits_box_history_entry_media" = "Media"; "lng_credits_box_history_entry_message" = "Message"; "lng_credits_box_history_entry_about" = "You can dispute this transaction {link}."; "lng_credits_box_history_entry_about_link" = "here"; "lng_credits_box_history_entry_reaction_name" = "Star Reaction"; "lng_credits_box_history_entry_subscription" = "Monthly subscription fee"; "lng_credits_box_history_entry_gift_upgrade" = "Collectible Upgrade"; "lng_credits_box_history_entry_gift_sold" = "Gift Sale"; "lng_credits_box_history_entry_gift_bought" = "Gift Purchase"; "lng_credits_box_history_entry_gift_sold_to" = "To"; "lng_credits_box_history_entry_gift_full_price" = "Full Price"; "lng_credits_box_history_entry_gift_bought_from" = "From"; "lng_credits_subscription_section" = "My subscriptions"; "lng_credits_box_subscription_title" = "Subscription"; "lng_credits_subscription_subtitle" = "{emoji} {cost} / month"; "lng_credits_subscriber_subtitle" = "appx. {total} per month"; "lng_credits_subscription_row_to" = "Subscription"; "lng_credits_subscription_row_to_bot" = "Bot"; "lng_credits_subscription_row_to_business" = "Business"; "lng_credits_subscription_row_from" = "Subscribed"; "lng_credits_subscription_row_next_on" = "Renews"; "lng_credits_subscription_row_next_off" = "Expires"; "lng_credits_subscription_row_next_none" = "Expired"; "lng_credits_subscription_on_button" = "Cancel Subscription"; "lng_credits_subscription_on_about" = "If you cancel now, you will still be able to access your subscription until {date}."; "lng_credits_subscription_off_button" = "Renew Subscription"; "lng_credits_subscription_off_rejoin_button" = "Subscribe again"; "lng_credits_subscription_off_about" = "You have canceled your subscription."; "lng_credits_subscription_off_by_bot_about" = "{bot} has canceled your subscription."; "lng_credits_subscription_status_on" = "renews on {date}"; "lng_credits_subscription_status_off" = "expires on {date}"; "lng_credits_subscription_status_none" = "expired on {date}"; "lng_credits_subscription_status_off_right" = "canceled"; "lng_credits_subscription_status_none_right" = "expired"; "lng_credits_subscription_status_off_by_bot_right" = "canceled\nby bot"; "lng_credits_small_balance_title#one" = "{count} Star Needed"; "lng_credits_small_balance_title#other" = "{count} Stars Needed"; "lng_credits_small_balance_about" = "Buy **Stars** and use them on **{bot}** and other miniapps."; "lng_credits_small_balance_reaction" = "Buy **Stars** and send them to {channel} to support their posts."; "lng_credits_small_balance_video_stream" = "Buy **Stars** to send them to {name} to support their stream."; "lng_credits_small_balance_subscribe" = "Buy **Stars** and subscribe to **{channel}** and other channels."; "lng_credits_small_balance_star_gift" = "Buy **Stars** to send gifts to {user} and other contacts."; "lng_credits_small_balance_for_message" = "Buy **Stars** to send messages to {user}."; "lng_credits_small_balance_for_messages" = "Buy **Stars** to send messages."; "lng_credits_small_balance_for_suggest" = "Buy **Stars** to suggest post to {channel}."; "lng_credits_small_balance_for_offer" = "Buy **Stars** to offer for this gift."; "lng_credits_small_balance_for_search" = "Buy **Stars** to search through public posts."; "lng_credits_small_balance_fallback" = "Buy **Stars** to unlock content and services on Telegram."; "lng_credits_purchase_blocked" = "Sorry, you can't purchase this item with Telegram Stars."; "lng_credits_enough" = "You have enough stars at the moment. {link}"; "lng_credits_enough_link" = "Buy anyway"; "lng_credits_gift_title" = "Gift Telegram Stars"; "lng_location_title" = "Location"; "lng_location_about" = "Display the location of your business on your account."; "lng_location_address" = "Enter Address"; "lng_location_set_map" = "Set Location on Map"; "lng_location_fallback" = "You can set your location on the map from your mobile device."; "lng_hours_title" = "Business Hours"; "lng_hours_about" = "Turn this on to show your opening hours schedule to your customers."; "lng_hours_show" = "Show Business Hours"; "lng_hours_time_zone" = "Time Zone"; "lng_hours_monday" = "Monday"; "lng_hours_tuesday" = "Tuesday"; "lng_hours_wednesday" = "Wednesday"; "lng_hours_thursday" = "Thursday"; "lng_hours_friday" = "Friday"; "lng_hours_saturday" = "Saturday"; "lng_hours_sunday" = "Sunday"; "lng_hours_closed" = "Closed"; "lng_hours_open_full" = "Open 24 hours"; "lng_hours_next_day" = "{time} (Next day)"; "lng_hours_on_next_day" = "Next day {time}"; "lng_hours_time_zone_title" = "Choose Time Zone"; "lng_hours_add_button" = "Add a Set of Hours"; "lng_hours_opening" = "Opening Time"; "lng_hours_closing" = "Closing Time"; "lng_hours_remove" = "Remove"; "lng_hours_about_day" = "Specify your working hours during the day."; "lng_replies_title" = "Quick Replies"; "lng_replies_about" = "Set up shortcuts with rich text and media to respond to messages faster."; "lng_replies_add" = "Add Quick Reply"; "lng_replies_add_title" = "New Quick Reply"; "lng_replies_add_shortcut" = "Add a shortcut for your reply."; "lng_replies_add_placeholder" = "Shortcut"; "lng_replies_add_exists" = "This shortcut already exists."; "lng_replies_empty_title" = "New Quick Reply"; "lng_replies_empty_about" = "Enter a message below that will be sent in chat when you type {shortcut}.\n\nYou can access Quick Replies in any chat by typing /."; "lng_replies_remove_title" = "Remove Shortcut"; "lng_replies_remove_text" = "You didn't create a quick reply message. Do you want to remove the shortcut?"; "lng_replies_edit_title" = "Edit Shortcut"; "lng_replies_edit_about" = "Change the name of your shortcut."; "lng_replies_message_placeholder" = "Add a Quick Reply"; "lng_replies_delete_sure" = "Are you sure you want to delete this quick reply with all its messages?"; "lng_replies_error_occupied" = "This shortcut is already used."; "lng_replies_edit_button" = "Edit Quick Replies"; "lng_greeting_title" = "Greeting Message"; "lng_greeting_about" = "Greet customers when they message you the first time or after a period of no activity."; "lng_greeting_enable" = "Send Greeting Message"; "lng_greeting_create" = "Create a Greeting Message"; "lng_greeting_recipients" = "Recipients"; "lng_greeting_select" = "Select chats or entire chat categories for sending greeting messages."; "lng_greeting_period_title" = "Period of no activity"; "lng_greeting_period_about" = "Choose how many days should pass after your last interaction with a recipient to send them a greeting in response to their message."; "lng_greeting_empty_title" = "New Greeting Message"; "lng_greeting_empty_about" = "Create greetings that will be automatically sent to new customers."; "lng_greeting_message_placeholder" = "Add a Greeting"; "lng_greeting_limit_reached" = "You have too many quick replies. Remove one to add a greeting message."; "lng_greeting_recipients_empty" = "Please choose at least one recipient."; "lng_away_title" = "Away Message"; "lng_away_about" = "Automatically reply with a message when you are away."; "lng_away_enable" = "Send Away Message"; "lng_away_create" = "Create an Away Message"; "lng_away_schedule" = "Schedule"; "lng_away_schedule_always" = "Send Always"; "lng_away_schedule_outside" = "Outside of Business Hours"; "lng_away_schedule_custom" = "Custom Schedule"; "lng_away_custom_start" = "Start Time"; "lng_away_custom_end" = "End Time"; "lng_away_offline_only" = "Only if Offline"; "lng_away_offline_only_about" = "Don't send the away message if you've recently been online."; "lng_away_recipients" = "Recipients"; "lng_away_select" = "Select chats or entire chat categories for sending an away message."; "lng_away_empty_title" = "New Away Message"; "lng_away_empty_about" = "Add messages that will be automatically sent when you are off."; "lng_away_message_placeholder" = "Add an Away Message"; "lng_away_limit_reached" = "You have too many quick replies. Remove one to add an away message."; "lng_business_edit_messages" = "Edit messages"; "lng_business_limit_reached#one" = "Limit of {count} message reached."; "lng_business_limit_reached#other" = "Limit of {count} messages reached."; "lng_chatbots_title" = "Chatbots"; "lng_chatbots_about" = "Add a bot to your account to help you automatically process and respond to the messages you receive. {link}"; "lng_chatbots_about_link" = "Learn more..."; "lng_chatbots_placeholder" = "Enter bot URL or username"; "lng_chatbots_add_about" = "Enter the link to the Telegram bot that you want to automatically process your chats."; "lng_chatbots_access_title" = "Chats accessible for the bot"; "lng_chatbots_all_except" = "All 1-to-1 Chats Except..."; "lng_chatbots_selected" = "Only Selected Chats"; "lng_chatbots_excluded_title" = "Excluded chats"; "lng_chatbots_exclude_button" = "Exclude Chats"; "lng_chatbots_included_title" = "Included chats"; "lng_chatbots_include_button" = "Select Chats"; "lng_chatbots_exclude_about" = "Select chats or entire chat categories which the bot will not have access to."; "lng_chatbots_permissions_title" = "Bot permissions"; "lng_chatbots_warning_title" = "Warning"; "lng_chatbots_warning_both_text" = "The bot {bot} will be able to **manage your gifts and stars**, including giving them away to other users."; "lng_chatbots_warning_gifts_text" = "The bot {bot} will be able to **manage your gifts**, including giving them away to other users."; "lng_chatbots_warning_stars_text" = "The bot {bot} will be able to **transfer your stars**."; "lng_chatbots_warning_username_text" = "The bot {bot} will be able to **set and remove usernames** for your account, which may result in the loss of your current username."; "lng_chatbots_manage_messages" = "Manage Messages"; "lng_chatbots_read" = "Read Messages"; "lng_chatbots_reply" = "Reply to Messages"; "lng_chatbots_mark_as_read" = "Mark Messages as Read"; "lng_chatbots_delete_sent" = "Delete Sent Messages"; "lng_chatbots_delete_received" = "Delete Received Messages"; "lng_chatbots_manage_profile" = "Manage Profile"; "lng_chatbots_edit_name" = "Edit Name"; "lng_chatbots_edit_bio" = "Edit Bio"; "lng_chatbots_edit_userpic" = "Edit Profile Picture"; "lng_chatbots_edit_username" = "Edit Username"; "lng_chatbots_manage_gifts" = "Manage Gifts and Stars"; "lng_chatbots_view_gifts" = "View Gifts"; "lng_chatbots_sell_gifts" = "Sell Gifts"; "lng_chatbots_gift_settings" = "Change Gift Settings"; "lng_chatbots_transfer_gifts" = "Transfer and Upgrade Gifts"; "lng_chatbots_transfer_stars" = "Transfer Stars"; "lng_chatbots_manage_stories" = "Manage Stories"; "lng_chatbots_remove" = "Remove Bot"; "lng_chatbots_not_found" = "Chatbot not found."; "lng_chatbots_not_supported" = "This bot doesn't support Telegram Business yet."; "lng_chatbots_add" = "Add"; "lng_chatbots_info_url" = "https://telegram.org/blog/telegram-business#chatbots-for-business"; "lng_chatbot_status_can_reply" = "bot manages this chat"; "lng_chatbot_status_paused" = "bot paused"; "lng_chatbot_status_views" = "bot has access to this chat"; "lng_chatbot_button_pause" = "Stop"; "lng_chatbot_button_resume" = "Start"; "lng_chatbot_menu_manage" = "Manage bot"; "lng_chatbot_menu_remove" = "Remove bot from this chat"; "lng_chatbot_menu_revoke" = "Revoke access to this chat"; "lng_chat_intro_title" = "Start Page"; "lng_chat_intro_subtitle" = "Customize your start page"; "lng_chat_intro_default_title" = "No messages here yet..."; "lng_chat_intro_default_message" = "Send a message or click on the greeting below"; "lng_chat_intro_enter_title" = "Enter Title"; "lng_chat_intro_enter_message" = "Enter Message"; "lng_chat_intro_choose_sticker" = "Choose Sticker"; "lng_chat_intro_random_sticker" = "Random"; "lng_chat_intro_about" = "You can customize the message people see before they start a chat with you."; "lng_chat_intro_reset" = "Reset to Default"; "lng_chat_links_title" = "Links to Chat"; "lng_chat_links_about" = "Give your customers short links that start a chat with you – and suggest the first message from them to you."; "lng_chat_links_create_link" = "Create a Link to Chat"; "lng_chat_links_footer" = "You can also use a simple link for a chat with you – {links}"; "lng_chat_links_footer_both" = "{username} or {link}"; "lng_chat_links_no_clicks" = "no clicks"; "lng_chat_links_clicks#one" = "{count} click"; "lng_chat_links_clicks#other" = "{count} clicks"; "lng_chat_link_new_title" = "New Link"; "lng_chat_link_edit_title" = "Edit Link"; "lng_chat_link_description" = "Add a message that will be entered in the message field for anyone who starts a chat with you using this link."; "lng_chat_link_placeholder" = "Add Preset Message"; "lng_chat_link_saved" = "Chat link saved."; "lng_chat_link_copy" = "Copy"; "lng_chat_link_share" = "Share"; "lng_chat_link_rename" = "Rename"; "lng_chat_link_delete" = "Delete"; "lng_chat_link_name" = "Link Name (optional)"; "lng_chat_link_name_about" = "Add a name for this link that only you will see."; "lng_chat_link_delete_sure" = "Are you sure you want to delete this chat link?"; "lng_chat_link_qr_title" = "Chat Link QR Code"; "lng_chat_link_qr_about" = "Everyone on Telegram can scan this code to contact you."; "lng_chat_link_copied" = "Chat link copied to clipboard."; "lng_boost_channel_button" = "Boost Channel"; "lng_boost_group_button" = "Boost Group"; "lng_boost_again_button" = "Boost Again"; "lng_boost_group_about" = "Boost your group to unlock additional\nappearance settings."; "lng_boost_level#one" = "Level {count}"; "lng_boost_level#other" = "Level {count}"; "lng_boost_level_unlocks#one" = "Level {count} Unlocks:"; "lng_boost_level_unlocks#other" = "Level {count} Unlocks:"; "lng_boost_channel_title_first" = "Enable stories for this channel"; "lng_boost_channel_title_first_group" = "Enable stories for group"; "lng_boost_channel_needs_unlock#one" = "{channel} needs **{count}** more boost to unlock new features."; "lng_boost_channel_needs_unlock#other" = "{channel} needs **{count}** more boosts to unlock new features."; //"lng_boost_channel_needs_first#one" = "{channel} needs **{count}** more boost to enable posting stories. Help make it possible!"; //"lng_boost_channel_needs_first#other" = "{channel} needs **{count}** more boosts to enable posting stories. Help make it possible!"; "lng_boost_channel_title_more" = "Help upgrade channel"; "lng_boost_channel_title_more_group" = "Help upgrade group"; //"lng_boost_channel_needs_more#one" = "{channel} needs **{count}** more boost to be able to {post}."; //"lng_boost_channel_needs_more#other" = "{channel} needs **{count}** more boosts to be able to {post}."; "lng_boost_channel_title_max" = "Maximum level reached"; "lng_boost_channel_you_title" = "You boosted {channel}!"; //"lng_boost_channel_you_first#one" = "This channel needs **{count}** more boost\nto enable stories."; //"lng_boost_channel_you_first#other" = "This channel needs **{count}** more boosts\nto enable stories."; //"lng_boost_channel_you_more#one" = "This channel needs **{count}** more boost\nto be able to {post}."; //"lng_boost_channel_you_more#other" = "This channel needs **{count}** more boosts\nto be able to {post}."; "lng_boost_channel_reached_first" = "This channel reached **Level 1** and can now post stories."; "lng_boost_channel_reached_more#one" = "This channel reached **Level {count}** and can now {post}."; "lng_boost_channel_reached_more#other" = "This channel reached **Level {count}** and can now {post}."; //"lng_boost_channel_you_first_group#one" = "This group needs **{count}** more boost\nto enable stories."; //"lng_boost_channel_you_first_group#other" = "This group needs **{count}** more boosts\nto enable stories."; //"lng_boost_channel_you_more_group#one" = "This group needs **{count}** more boost\nto be able to {post}."; //"lng_boost_channel_you_more_group#other" = "This group needs **{count}** more boosts\nto be able to {post}."; "lng_boost_channel_reached_first_group" = "This group reached **Level 1** and can now post stories."; "lng_boost_channel_reached_more_group#one" = "This group reached **Level {count}** and can now {post}."; "lng_boost_channel_reached_more_group#other" = "This group reached **Level {count}** and can now {post}."; "lng_boost_channel_post_stories#one" = "post **{count} story** per day"; "lng_boost_channel_post_stories#other" = "post **{count} stories** per day"; "lng_boost_channel_features" = "Your boosts will help {channel} to unlock new features."; "lng_boost_group_lift_restrictions" = "Boost the group to remove messaging restrictions."; "lng_boost_group_lift_restrictions_many#one" = "Boost the group **{count} time** to remove messaging restrictions."; "lng_boost_group_lift_restrictions_many#other" = "Boost the group **{count} times** to remove messaging restrictions."; "lng_boost_error_gifted_title" = "Can't boost with gifted Premium!"; "lng_boost_error_gifted_text" = "Because your **Telegram Premium** subscription was gifted to you, you can't use it to boost channels."; "lng_boost_error_gifted_text_group" = "Because your **Telegram Premium** subscription was gifted to you, you can't use it to boost groups."; "lng_boost_need_more" = "More boosts needed"; "lng_boost_need_more_text#one" = "To boost {channel}, gift **Telegram Premium** to a friend and get **{count}** boost."; "lng_boost_need_more_text#other" = "To boost {channel}, gift **Telegram Premium** to a friend and get **{count}** boosts."; "lng_boost_need_more_again#one" = "To boost {channel} again, gift **Telegram Premium** to a friend and get **{count}** additional boost."; "lng_boost_need_more_again#other" = "To boost {channel} again, gift **Telegram Premium** to a friend and get **{count}** additional boosts."; "lng_boost_error_already_title" = "Already Boosted!"; "lng_boost_error_already_text" = "You are already boosting this channel."; "lng_boost_error_already_text_group" = "You are already boosting this group."; "lng_boost_error_premium_title" = "Premium needed"; "lng_boost_error_premium_text_group" = "Only **Telegram Premium** subscribers can boost groups. Do you want to subscribe to **Telegram Premium**?"; "lng_boost_error_premium_text" = "Only **Telegram Premium** subscribers can boost channels. Do you want to subscribe to **Telegram Premium**?"; "lng_boost_error_premium_yes" = "Yes"; "lng_boost_error_flood_title" = "Can't boost too often!"; "lng_boost_error_flood_text_group" = "You can change the group you boost only once a day. Next time you can boost is in {left}."; "lng_boost_error_flood_text" = "You can only change the channel you boost once a day. You will be able to boost in {left}."; "lng_boost_now_instead" = "You currently boost {channel}. Do you want to boost {other} instead?"; "lng_boost_now_replace" = "Replace"; "lng_boost_reassign_title" = "Reassign boost"; "lng_boost_reassign_text" = "To boost {channel}, reassign a previous boost or {gift}."; "lng_boost_reassign_gift#one" = "gift **Telegram Premium** to a friend to get **{count}** additional boost"; "lng_boost_reassign_gift#other" = "gift **Telegram Premium** to a friend to get **{count}** additional boosts"; "lng_boost_remove_title" = "Remove your boost from"; "lng_boost_reassign_button" = "Reassign"; "lng_boost_available_in" = "available in {duration}"; "lng_boost_available_in_toast#one" = "Wait until the boost is available or get **{count}** more boost by gifting a **Telegram Premium** subscription."; "lng_boost_available_in_toast#other" = "Wait until the boost is available or get **{count}** more boosts by gifting a **Telegram Premium** subscription."; "lng_boost_reassign_done#one" = "{count} boost is reassigned from {channels}."; "lng_boost_reassign_done#other" = "{count} boosts are reassigned from {channels}."; "lng_boost_reassign_channels#one" = "{count} channel"; "lng_boost_reassign_channels#other" = "{count} channels"; "lng_boost_reassign_groups#one" = "{count} group"; "lng_boost_reassign_groups#other" = "{count} groups"; "lng_boost_reassign_mixed#one" = "{count} group or channel"; "lng_boost_reassign_mixed#other" = "{count} groups and channels"; "lng_boost_channel_title_color" = "Enable colors"; "lng_boost_channel_needs_level_color#one" = "Your channel needs to reach **Level {count}** to change channel color."; "lng_boost_channel_needs_level_color#other" = "Your channel needs to reach **Level {count}** to change channel color."; "lng_boost_channel_title_wallpaper" = "Enable wallpapers"; "lng_boost_channel_needs_level_wallpaper#one" = "Your channel needs to reach **Level {count}** to change channel wallpaper."; "lng_boost_channel_needs_level_wallpaper#other" = "Your channel needs to reach **Level {count}** to change channel wallpaper."; "lng_boost_group_needs_level_wallpaper#one" = "Your group needs to reach **Level {count}** to change group wallpaper."; "lng_boost_group_needs_level_wallpaper#other" = "Your group needs to reach **Level {count}** to change group wallpaper."; "lng_boost_channel_title_status" = "Enable emoji status"; "lng_boost_channel_needs_level_status#one" = "Your channel needs to reach **Level {count}** to set emoji status."; "lng_boost_channel_needs_level_status#other" = "Your channel needs to reach **Level {count}** to set emoji status."; "lng_boost_group_needs_level_status#one" = "Your group needs to reach **Level {count}** to set emoji status."; "lng_boost_group_needs_level_status#other" = "Your group needs to reach **Level {count}** to set emoji status."; "lng_boost_channel_title_reactions" = "Custom reactions"; "lng_boost_channel_needs_level_reactions#one" = "Your channel needs to reach **Level {count}** to add **{same_count}** custom emoji as a reaction."; "lng_boost_channel_needs_level_reactions#other" = "Your channel needs to reach **Level {count}** to add **{same_count}** custom emoji as reactions."; "lng_boost_channel_title_cpm" = "Boost Channel"; "lng_boost_channel_needs_level_cpm#one" = "Your channel needs to reach **Level {count}** to switch off ads."; "lng_boost_channel_needs_level_cpm#other" = "Your channel needs to reach **Level {count}** to switch off ads."; "lng_boost_group_title_emoji" = "Enable emoji pack"; "lng_boost_group_needs_level_emoji#one" = "Your group needs to reach **Level {count}** to set emoji pack."; "lng_boost_group_needs_level_emoji#other" = "Your group needs to reach **Level {count}** to set emoji pack."; "lng_boost_channel_title_wear" = "Wear Item"; "lng_boost_channel_needs_level_wear#one" = "Your channel needs **Level {count}** to wear collectibles."; "lng_boost_channel_needs_level_wear#other" = "Your channel needs **Level {count}** to wear collectibles."; "lng_boost_channel_ask" = "Ask your **Premium** subscribers to boost your channel with this link:"; "lng_boost_channel_ask_button" = "Copy Link"; //"lng_boost_channel_or" = "or"; //"lng_boost_channel_gifting" = "Boost your channel by gifting your subscribers Telegram Premium. {link}"; //"lng_boost_channel_gifting_link" = "Get boosts >"; "lng_boost_group_ask" = "Ask your **Premium** members to boost your group with this link:"; //"lng_boost_group_gifting" = "Boost your group by gifting your members Telegram Premium. {link}"; "lng_boost_channel_title_autotranslate" = "Autotranslation of Messages"; "lng_boost_channel_needs_level_autotranslate#one" = "Your channel needs to reach **Level {count}** to enable autotranslation of messages."; "lng_boost_channel_needs_level_autotranslate#other" = "Your channel needs to reach **Level {count}** to enable autotranslation of messages."; "lng_feature_stories#one" = "**{count}** Story Per Day"; "lng_feature_stories#other" = "**{count}** Stories Per Day"; "lng_feature_reactions#one" = "**{count}** Custom Reaction"; "lng_feature_reactions#other" = "**{count}** Custom Reactions"; "lng_feature_name_color_channel#one" = "**{count}** Channel Name Color"; "lng_feature_name_color_channel#other" = "**{count}** Channel Name Colors"; "lng_feature_link_style_channel#one" = "**{count}** Style for Links and Quotes"; "lng_feature_link_style_channel#other" = "**{count}** Styles for Links and Quotes"; "lng_feature_link_emoji" = "Custom Logo for Links and Quotes"; "lng_feature_emoji_status" = "**1000+** Emoji Statuses"; "lng_feature_backgrounds_channel#one" = "**{count}** Channel Background"; "lng_feature_backgrounds_channel#other" = "**{count}** Channel Backgrounds"; "lng_feature_custom_background_channel" = "Custom Channel Background"; "lng_feature_backgrounds_group#one" = "**{count}** Group Background"; "lng_feature_backgrounds_group#other" = "**{count}** Group Backgrounds"; "lng_feature_custom_background_group" = "Custom Group Background"; "lng_feature_custom_emoji_pack" = "Custom Emoji Pack"; "lng_feature_transcribe" = "Voice-to-Text Conversion"; "lng_feature_autotranslate" = "Autotranslation of Messages"; "lng_feature_profile_color_channel#one" = "**{count}** Color for Channel Cover"; "lng_feature_profile_color_channel#other" = "**{count}** Colors for Channel Cover"; "lng_feature_profile_color_group#one" = "**{count}** Color for Group Cover"; "lng_feature_profile_color_group#other" = "**{count}** Colors for Group Cover"; "lng_feature_profile_icon_channel" = "Custom Logo for Channel Cover"; "lng_feature_profile_icon_group" = "Custom Logo for Group Cover"; "lng_edit_topics_enable" = "Enable Topics"; "lng_edit_topics_about" = "The group chat will be divided into topics created by admins or users."; "lng_edit_topics_layout" = "Topics layout"; "lng_edit_topics_layout_about" = "Choose how topics appear for all members."; "lng_edit_topics_tabs" = "Tabs"; "lng_edit_topics_list" = "List"; "lng_giveaway_new_title" = "Boosts via Gifts"; "lng_giveaway_new_about" = "Get more boosts for your channel by gifting Premium to your subscribers."; "lng_giveaway_new_about_group" = "Get more boosts for your group by gifting Premium to your members."; "lng_giveaway_credits_new_about" = "Get more boosts and subscribers for your channel by giving away prizes."; "lng_giveaway_credits_new_about_group" = "Get more boosts and members for your group by giving away prizes."; "lng_giveaway_create_option" = "Create Giveaway"; "lng_giveaway_create_subtitle" = "winners are chosen randomly"; "lng_giveaway_award_option" = "Award Specific Users"; "lng_giveaway_award_subtitle" = "Select recipients >"; "lng_giveaway_award_chosen#one" = "{count} recipient >"; "lng_giveaway_award_chosen#other" = "{count} recipients >"; "lng_giveaway_quantity_title" = "Quantity of prizes"; "lng_giveaway_quantity#one" = "{count} Boost"; "lng_giveaway_quantity#other" = "{count} Boosts"; "lng_giveaway_quantity_about" = "Choose how many Premium subscriptions to give away and boosts to receive."; "lng_giveaway_channels_title" = "Channels included in the giveaway"; "lng_giveaway_channels_this#one" = "this channel will receive {count} boost"; "lng_giveaway_channels_this#other" = "this channel will receive {count} boosts"; "lng_giveaway_channels_this_group#one" = "this group will receive {count} boost"; "lng_giveaway_channels_this_group#other" = "this group will receive {count} boosts"; "lng_giveaway_channels_add" = "Add Group or Channel"; "lng_giveaway_channels_about" = "Choose the groups and channels users need to join to take part in the giveaway."; "lng_giveaway_users_title" = "Users eligible for the giveaway"; "lng_giveaway_users_all" = "All subscribers"; "lng_giveaway_users_all_group" = "All members"; "lng_giveaway_users_from_all_countries" = "from all countries"; "lng_giveaway_users_from_one_country" = "from {country}"; "lng_giveaway_users_from_countries#one" = "from {count} country"; "lng_giveaway_users_from_countries#other" = "from {count} countries"; "lng_giveaway_users_new" = "Only new subscribers"; "lng_giveaway_users_new_group" = "Only new members"; "lng_giveaway_users_about" = "Choose if you want to limit the giveaway only to those who joined the channel after the giveaway started or to users from specific countries."; "lng_giveaway_users_about_group" = "Choose if you want to limit the giveaway only to those who joined the group after the giveaway started or to members from specific countries."; "lng_giveaway_start" = "Start Giveaway"; "lng_giveaway_award" = "Gift Premium"; "lng_giveaway_random_button" = "Choose randomly"; "lng_giveaway_start_sure" = "Are you sure you want to start this prepaid giveaway now? This action cannot be undone."; "lng_giveaway_date_title" = "Date when giveaway ends"; "lng_giveaway_date" = "Date and Time"; "lng_giveaway_date_about#one" = "Choose when {count} subscriber of your channel will be randomly selected to receive Telegram Premium."; "lng_giveaway_date_about#other" = "Choose when {count} subscribers of your channel will be randomly selected to receive Telegram Premium."; "lng_giveaway_date_about_group#one" = "Choose when {count} members of your group will be randomly selected to receive Telegram Premium."; "lng_giveaway_date_about_group#other" = "Choose when {count} members of your group will be randomly selected to receive Telegram Premium."; "lng_giveaway_duration_title#one" = "Duration of Premium subscription"; "lng_giveaway_duration_title#other" = "Duration of Premium subscriptions"; "lng_giveaway_duration_price" = "{price} x {amount}"; "lng_giveaway_date_select" = "Select Date and Time"; "lng_giveaway_date_confirm" = "Confirm"; "lng_giveaway_recipients_save" = "Save Recipients"; "lng_giveaway_recipients_deselect" = "Deselect All"; "lng_giveaway_maximum_countries_error#one" = "You can select up to {count} country."; "lng_giveaway_maximum_countries_error#other" = "You can select up to {count} countries."; "lng_giveaway_maximum_channels_error#one" = "You can select {count} group or channel."; "lng_giveaway_maximum_channels_error#other" = "You can select up to {count} groups and channels."; "lng_giveaway_maximum_users_error#one" = "You can select up to {count} subscribers."; "lng_giveaway_maximum_users_error#other" = "You can select up to {count} subscribers."; "lng_giveaway_channels_confirm_title" = "Channel is Private"; "lng_giveaway_channels_confirm_about" = "Are you sure you want to add a private channel? Users won't be able to join it without an invite link."; "lng_giveaway_additional_prizes" = "Additional prizes"; "lng_giveaway_additional_about" = "Turn this on if you want to give the winners your own prizes in addition to Premium subscriptions."; "lng_giveaway_additional_prizes_ph" = "Enter your prize"; "lng_giveaway_prizes_just_premium#one" = "All prizes: **{count}** Telegram Premium subscription {duration}."; "lng_giveaway_prizes_just_premium#other" = "All prizes: **{count}** Telegram Premium subscriptions {duration}."; "lng_giveaway_prizes_additional#one" = "All prizes: **{count}** {prize} with Telegram Premium subscription {duration}."; "lng_giveaway_prizes_additional#other" = "All prizes: **{count}** {prize} with Telegram Premium subscriptions {duration}."; "lng_giveaway_additional_credits_about" = "Turn this on if you want to give the winners your own prizes in addition to Stars."; "lng_giveaway_prizes_just_credits#one" = "All prizes: **{count}** Star."; "lng_giveaway_prizes_just_credits#other" = "All prizes: **{count}** Stars."; "lng_giveaway_prizes_additional_credits#one" = "All prizes: **{count}** {prize} with {amount}."; "lng_giveaway_prizes_additional_credits#other" = "All prizes: **{count}** {prize} with {amount}."; "lng_giveaway_prizes_additional_credits_amount#one" = "{count} Star"; "lng_giveaway_prizes_additional_credits_amount#other" = "{count} Stars"; "lng_giveaway_show_winners" = "Show winners"; "lng_giveaway_show_winners_about" = "Choose whether to make the list of winners public when the giveaway ends."; "lng_giveaway_created_title" = "Giveaway created"; "lng_giveaway_created_body" = "Check your channels' {link} to see how this giveaway boosted your channel."; "lng_giveaway_created_body_group" = "Check your groups' {link} to see how this giveaway boosted your group."; "lng_giveaway_awarded_title" = "Premium subscriptions gifted"; "lng_giveaway_awarded_body" = "Check your channels' {link} to see how gifts boosted your channel."; "lng_giveaway_awarded_body_group" = "Check your groups' {link} to see how gifts boosted your group."; "lng_giveaway_created_link" = "Statistics"; "lng_giveaway_credits_options_title" = "Stars to distribute"; "lng_giveaway_credits_option_status#one" = "{count} per user"; "lng_giveaway_credits_option_status#other" = "{count} per user"; "lng_giveaway_credits_options_about" = "Choose how many stars to give away and how many boosts to receive for 1 year."; "lng_giveaway_credits_quantity_title" = "Number of winners"; "lng_giveaway_credits_quantity_about" = "Choose how many winners you want to distribute stars among."; "lng_prize_title" = "Congratulations!"; "lng_prize_about" = "You won a prize in a giveaway organized by {channel}."; "lng_prize_duration" = "Your prize is a **Telegram Premium** subscription {duration}."; "lng_prize_credits" = "Your prize is {amount}."; "lng_prize_credits_amount#one" = "{count} Star"; "lng_prize_credits_amount#other" = "{count} Stars"; "lng_prize_gift_about" = "You've received a gift from {channel}."; "lng_prize_gift_duration" = "Your gift is a **Telegram Premium** subscription {duration}."; "lng_prize_open" = "Open Gift Link"; "lng_prize_unclaimed_title" = "Unclaimed Prize"; "lng_prize_unclaimed_about" = "You have an unclaimed prize from a giveaway by {channel}."; "lng_prize_unclaimed_duration" = "This prize is a **Telegram Premium** subscription {duration}."; "lng_prizes_title#one" = "Giveaway Prize"; "lng_prizes_title#other" = "Giveaway Prizes"; "lng_prizes_additional#one" = "**{count}** {prize}"; "lng_prizes_additional#other" = "**{count}** {prize}"; "lng_prizes_additional_with" = "with"; "lng_prizes_about#one" = "**{count}** Telegram Premium Subscription {duration}."; "lng_prizes_about#other" = "**{count}** Telegram Premium Subscriptions {duration}."; "lng_prizes_credits_about_single" = "**{amount}** will be distributed to the **1** winner."; "lng_prizes_credits_about#one" = "**{amount}** will be distributed among {count} winner."; "lng_prizes_credits_about#other" = "**{amount}** will be distributed among {count} winners."; "lng_prizes_credits_about_amount#one" = "{count} Star"; "lng_prizes_credits_about_amount#other" = "{count} Stars"; "lng_prizes_participants" = "Participants"; "lng_prizes_participants_all#one" = "All subscribers of the channel:"; "lng_prizes_participants_all#other" = "All subscribers of the channels:"; "lng_prizes_participants_all_group#one" = "All members of the group:"; "lng_prizes_participants_all_group#other" = "All members of the groups:"; "lng_prizes_participants_all_mixed#one" = "All members of the group:"; "lng_prizes_participants_all_mixed#other" = "All members of the groups and channels:"; "lng_prizes_participants_new#one" = "All users who joined the channel below after this announcement:"; "lng_prizes_participants_new#other" = "All users who joined the channels below after this announcement:"; "lng_prizes_participants_new_group#one" = "All users who joined the group below after this date:"; "lng_prizes_participants_new_group#other" = "All users who joined the groups below after this date:"; "lng_prizes_participants_new_mixed#one" = "All users who joined the group below after this date:"; "lng_prizes_participants_new_mixed#other" = "All users who joined the groups and channels below after this date:"; "lng_prizes_countries" = "from {countries}"; "lng_prizes_countries_and_one" = "{countries}, {country}"; "lng_prizes_countries_and_last" = "{countries} and {country}"; "lng_prizes_date" = "Winners Selection Date"; "lng_prizes_how_works" = "Learn more"; "lng_prizes_how_title" = "About this giveaway"; "lng_prizes_end_title" = "Giveaway ended"; "lng_prizes_how_text" = "This giveaway is sponsored by {admins}."; "lng_prizes_end_text" = "This giveaway was sponsored by {admins}."; "lng_prizes_admins#one" = "the admins of {channel}, who acquired **{count} Telegram Premium** subscription {duration} for its followers"; "lng_prizes_admins#other" = "the admins of {channel}, who acquired **{count} Telegram Premium** subscriptions {duration} for its followers"; "lng_prizes_admins_group#one" = "the admins of {channel}, who acquired **{count} Telegram Premium** subscription {duration} for its members"; "lng_prizes_admins_group#other" = "the admins of {channel}, who acquired **{count} Telegram Premium** subscriptions {duration} for its members"; "lng_prizes_credits_admins" = "the admins of {channel}, who aquired **{amount}** for its followers"; "lng_prizes_credits_admins_group" = "the admins of {channel}, who aquired **{amount}** for its members"; "lng_prizes_credits_admins_amount#one" = "{count} Star"; "lng_prizes_credits_admins_amount#other" = "{count} Stars"; "lng_prizes_additional_added#one" = "{channel} also included **{count} {prize}** in the prize. Admins of the channel are responsible for delivering this prize."; "lng_prizes_additional_added#other" = "{channel} also included **{count} {prize}** in the prizes. Admins of the channel are responsible for delivering these prizes."; "lng_prizes_additional_added_group#one" = "{channel} also included **{count} {prize}** in the prize. Admins of the group are responsible for delivering this prize."; "lng_prizes_additional_added_group#other" = "{channel} also included **{count} {prize}** in the prizes. Admins of the group are responsible for delivering these prizes."; "lng_prizes_how_when_finish" = "On {date}, Telegram will automatically select {winners}."; "lng_prizes_end_when_finish" = "On {date}, Telegram automatically selected {winners}."; "lng_prizes_end_activated#one" = "**{count}** winner already used their gift link."; "lng_prizes_end_activated#other" = "**{count}** of the winners already used their gift links."; "lng_prizes_winners_all_of_one#one" = "{count} random subscriber of {channel}"; "lng_prizes_winners_all_of_one#other" = "{count} random subscribers of {channel}"; "lng_prizes_winners_all_of_one_group#one" = "{count} random member of {channel}"; "lng_prizes_winners_all_of_one_group#other" = "{count} random members of {channel}"; "lng_prizes_winners_all_of_many#one" = "{count} random subscriber of {channel} and other listed groups and channels"; "lng_prizes_winners_all_of_many#other" = "{count} random subscribers of {channel} and other listed groups and channels"; "lng_prizes_winners_all_of_many_group#one" = "{count} random member of {channel} and other listed groups and channels"; "lng_prizes_winners_all_of_many_group#other" = "{count} random members of {channel} and other listed groups and channels"; "lng_prizes_winners_new_of_one#one" = "{count} random user that joined {channel} after {start_date}"; "lng_prizes_winners_new_of_one#other" = "{count} random users that joined {channel} after {start_date}"; "lng_prizes_winners_new_of_many#one" = "{count} random user that joined {channel} and other listed groups and channels after {start_date}"; "lng_prizes_winners_new_of_many#other" = "{count} random users that joined {channel} and other listed groups and channels after {start_date}"; "lng_prizes_how_participate_one" = "To take part in this giveaway please join the channel {channel} before {date}."; "lng_prizes_how_participate_many" = "To take part in this giveaway please join channel {channel} and other listed groups and channels before {date}."; "lng_prizes_how_no_admin" = "You are not eligible to participate in this giveaway because you are an admin of a participating channel ({channel})."; "lng_prizes_how_no_admin_group" = "You are not eligible to participate in this giveaway, because you are an admin of participating group ({channel})."; "lng_prizes_how_no_joined" = "You are not eligible to participate in this giveaway because you joined this channel on {date}, which is before the giveaway started."; "lng_prizes_how_no_joined_group" = "You are not eligible to participate in this giveaway, because you joined this group on {date}, which is before the contest started."; "lng_prizes_how_no_country" = "You are not eligible to participate in this giveaway because your country is not included in the terms of the giveaway."; "lng_prizes_how_yes_joined_one" = "You are participating in this giveaway because you joined the channel {channel}."; "lng_prizes_how_yes_joined_many" = "You are participating in this giveaway because you joined the channel {channel} (and other listed groups and channels)."; "lng_prizes_you_won" = "You won a prize in this giveaway {cup}"; "lng_prizes_you_won_credits" = "You won {amount} in this giveaway {cup}"; "lng_prizes_you_won_credits_amount#one" = "{count} Star"; "lng_prizes_you_won_credits_amount#other" = "{count} Stars"; "lng_prizes_view_prize" = "View my prize"; "lng_prizes_you_didnt" = "You didn't win a prize in this giveaway."; "lng_prizes_cancelled" = "The channel canceled the prizes by refunding the payment for them."; "lng_prizes_cancelled_group" = "The group canceled the prizes by refunding the payment for them."; "lng_prizes_badge" = "x{amount}"; "lng_prizes_results_title" = "Winners Selected!"; "lng_prizes_results_title_one" = "Winner Selected!"; "lng_prizes_results_about#one" = "**{count}** winner of the {link} was randomly selected by Telegram."; "lng_prizes_results_about#other" = "**{count}** winners of the {link} were randomly selected by Telegram."; "lng_prizes_results_link" = "Giveaway"; "lng_prizes_results_winner" = "Winner"; "lng_prizes_results_winners" = "Winners"; "lng_prizes_results_more#one" = "and {count} more!"; "lng_prizes_results_more#other" = "and {count} more!"; "lng_prizes_results_one" = "The winner received their gift link in a private message."; "lng_prizes_results_all" = "All winners received gift links in private messages."; "lng_prizes_credits_results_one#one" = "The winner received {count} Star."; "lng_prizes_credits_results_one#other" = "The winner received {count} Stars."; "lng_prizes_credits_results_all#one" = "All winners received {count} Star in total."; "lng_prizes_credits_results_all#other" = "All winners received {count} Stars in total."; "lng_prizes_results_some" = "Some winners couldn't be selected."; "lng_gift_link_title" = "Gift Link"; "lng_gift_link_about" = "This link allows you to activate\na **Telegram Premium** subscription."; "lng_gift_link_label_from" = "From"; "lng_gift_link_label_to" = "To"; "lng_gift_link_label_to_unclaimed" = "No recipient"; "lng_gift_link_label_gift" = "Gift"; "lng_gift_link_gift_premium" = "Telegram Premium {duration}"; "lng_gift_link_label_reason" = "Reason"; "lng_gift_link_reason_giveaway" = "Giveaway"; "lng_gift_link_reason_unclaimed" = "Incomplete Giveaway"; "lng_gift_link_reason_chosen" = "You were selected by the channel"; "lng_gift_link_label_date" = "Date"; "lng_gift_link_label_first_sale" = "First Sale"; "lng_gift_link_label_last_sale" = "Last Sale"; "lng_gift_link_label_value" = "Value"; "lng_gift_link_also_send" = "You can also {link} to a friend as a gift."; "lng_gift_link_also_send_link" = "send this link"; "lng_gift_link_use" = "Use Link"; "lng_gift_link_already_title" = "You already have Telegram Premium"; "lng_gift_link_already_about" = "You can activate this link after {date} or {link} to a friend."; "lng_gift_link_already_link" = "send the link"; "lng_gift_link_used_title" = "Used Gift Link"; "lng_gift_link_used_about" = "This link was used to activate\na **Telegram Premium** subscription."; "lng_gift_link_used_footer" = "This link was used on {date}."; "lng_gift_link_expired" = "Gift code link expired"; "lng_gift_link_pending_about" = "This link allows {user} to activate\na **Telegram Premium** subscription."; "lng_gift_link_pending_toast" = "Only the recipient can see the link."; "lng_gift_link_pending_footer" = "This link hasn't been activated yet."; "lng_gift_stars_title#one" = "{count} Star"; "lng_gift_stars_title#other" = "{count} Stars"; "lng_gift_stars_outgoing" = "With Stars, {user} will be able to unlock content and services on Telegram."; "lng_gift_stars_incoming" = "Use Stars to unlock content and services on Telegram."; "lng_gift_until" = "Until"; "lng_gift_ton_amount#one" = "{count} TON"; "lng_gift_ton_amount#other" = "{count} TON"; "lng_gift_premium_title" = "Premium Gift"; "lng_gift_premium_text#one" = "Subscribe to **Telegram Premium** to send up to **{count}** of these gifts and unlock access to multiple additional features."; "lng_gift_premium_text#other" = "Subscribe to **Telegram Premium** to send up to **{count}** of these gifts and unlock access to multiple additional features."; "lng_gift_premium_or_stars" = "Gift Premium or Stars"; "lng_gift_premium_subtitle" = "Gift Premium"; "lng_gift_premium_about" = "Give {name} access to exclusive features with Telegram Premium. {features}"; "lng_gift_premium_features" = "See Features >"; "lng_gift_premium_label" = "Premium"; "lng_gift_premium_by_stars" = "or {amount}"; "lng_gift_stars_subtitle" = "Gift Stars"; "lng_gift_stars_about" = "Give {name} gifts that can be kept on your profile or converted to Stars. {link}"; "lng_gift_stars_about_collectibles" = "Collectible gifts are unique digital items you can exchange or sell. {link}"; "lng_gift_stars_link" = "What are Stars >"; "lng_gift_stars_limited" = "limited"; "lng_gift_stars_sold_out" = "sold out"; "lng_gift_stars_resale" = "resale"; "lng_gift_stars_on_sale" = "on sale"; "lng_gift_on_sale_for" = "On sale for {price}"; "lng_gift_stars_premium" = "premium"; "lng_gift_stars_auction" = "auction"; "lng_gift_stars_auction_join" = "Join"; "lng_gift_stars_auction_view" = "View"; "lng_gift_stars_auction_soon" = "soon"; "lng_gift_stars_auction_upgraded" = "upgraded"; "lng_gift_stars_your_left#one" = "{count} left"; "lng_gift_stars_your_left#other" = "{count} left"; "lng_gift_stars_your_finished" = "none left"; "lng_gift_stars_tabs_all" = "All Gifts"; "lng_gift_stars_tabs_my" = "My Gifts"; "lng_gift_stars_tabs_my_empty" = "You don't have any gifts you can use as a profile cover."; "lng_gift_stars_tabs_my_empty_next" = "Browse gifts available for purchase {emoji}"; "lng_gift_stars_tabs_collectibles" = "Collectibles"; "lng_gift_send_title" = "Send a Gift"; "lng_gift_send_message" = "Enter Message"; "lng_gift_send_anonymous" = "Hide My Name"; "lng_gift_send_pay_with_stars" = "Pay with {amount}"; "lng_gift_send_stars_balance" = "Your balance is {amount}. {link}"; "lng_gift_send_stars_balance_link" = "Get More Stars >"; "lng_gift_send_anonymous_self" = "Hide my name and message from visitors to my profile."; "lng_gift_send_anonymous_about" = "You can hide your name and message from visitors to {user}'s profile. {recipient} will still see your name and message."; "lng_gift_send_anonymous_about_paid" = "You can hide your name from visitors to {user}'s profile. {recipient} will still see your name."; "lng_gift_send_anonymous_about_channel" = "You can hide your name and message from all visitors of this channel except its admins."; "lng_gift_send_unique" = "Make Unique for {price}"; "lng_gift_send_unique_about" = "Enable this to let {user} turn your gift into a unique collectible. {link}"; "lng_gift_send_unique_about_channel" = "Enable this to let the admins of {name} turn your gift into a unique collectible. {link}"; "lng_gift_send_unique_link" = "Learn More >"; "lng_gift_send_premium_about" = "Only {user} will see your message."; "lng_gift_send_limited_sold#one" = "{count} sold"; "lng_gift_send_limited_sold#other" = "{count} sold"; "lng_gift_send_limited_left#one" = "{count} left"; "lng_gift_send_limited_left#other" = "{count} left"; "lng_gift_send_button" = "Send a Gift for {cost}"; "lng_gift_send_button_self" = "Buy a Gift for {cost}"; "lng_gift_buy_resale_title" = "Buy {name}"; "lng_gift_buy_resale_button" = "Buy for {cost}"; "lng_gift_buy_resale_equals" = "Equals to {cost}"; "lng_gift_buy_resale_only_ton" = "The seller only accepts TON as payment."; "lng_gift_buy_resale_pay_stars" = "Pay in Stars"; "lng_gift_buy_resale_pay_ton" = "Pay in TON"; "lng_gift_buy_resale_confirm" = "Do you want to buy {name} for {price} and gift it to {user}?"; "lng_gift_buy_resale_confirm_self" = "Do you want to buy {name} for {price}?"; "lng_gift_buy_price_change_title" = "Price change!"; "lng_gift_buy_price_change_text" = "This gift price was changed and now is {price}. Do you still want to buy?"; "lng_gift_sent_title" = "Gift Sent!"; "lng_gift_sent_resale_done" = "{user} has been notified about your gift."; "lng_gift_sent_resale_done_self" = "{gift} is now yours."; "lng_gift_sent_about#one" = "You spent **{count}** Star from your balance."; "lng_gift_sent_about#other" = "You spent **{count}** Stars from your balance."; "lng_gift_sent_finished#one" = "You've already sent **{count}** of these gifts, and it's the limit."; "lng_gift_sent_finished#other" = "You've already sent **{count}** of these gifts, and it's the limit."; "lng_gift_sent_remains#one" = "You can send **{count}** more."; "lng_gift_sent_remains#other" = "You can send **{count}** more."; "lng_gift_limited_of_one" = "unique"; "lng_gift_limited_of_count" = "1 of {amount}"; "lng_gift_collectible_tag" = "gift"; "lng_gift_burned_tag" = "burned"; "lng_gift_crafted_tag" = "crafted"; "lng_gift_uncommon_tag" = "uncommon"; "lng_gift_rare_tag" = "rare"; "lng_gift_epic_tag" = "epic"; "lng_gift_legendary_tag" = "legendary"; "lng_gift_view_unpack" = "Unpack"; "lng_gift_anonymous_hint" = "Only you can see the sender's name."; "lng_gift_anonymous_hint_channel" = "Only admins of this channel can see the sender's name."; "lng_gift_hidden_hint" = "This gift is hidden. Only you can see it."; "lng_gift_hidden_unique" = "This gift is not displayed on your page."; "lng_gift_visible_hint" = "This gift is visible on your page."; "lng_gift_burned_message" = "This gift was burned in crafting."; "lng_gift_hidden_hint_channel" = "This gift is hidden from visitors of your channel."; "lng_gift_visible_hint_channel" = "This gift is visible in your channel's Gifts."; "lng_gift_in_blockchain" = "This gift is in TON blockchain. {link}"; "lng_gift_in_blockchain_link_arrow" = "View {arrow}"; "lng_gift_visible_hide_arrow" = "Hide {arrow}"; "lng_gift_visible_show_arrow" = "Show {arrow}"; "lng_gift_show_on_page" = "Display on my Page"; "lng_gift_show_on_channel" = "Display in channel's Gifts"; "lng_gift_availability" = "Availability"; "lng_gift_from_hidden" = "Hidden User"; "lng_gift_subtitle_birthdays" = "Birthdays"; "lng_gift_list_birthday_status_today" = "{emoji} Birthday today"; "lng_gift_list_birthday_status_yesterday" = "Birthday yesterday"; "lng_gift_list_birthday_status_tomorrow" = "Birthday tomorrow"; "lng_gift_self_status" = "buy yourself a gift"; "lng_gift_self_title" = "Buy a Gift"; "lng_gift_self_about" = "Buy yourself a gift to display on your page or reserve for later.\n\nLimited-edition gifts upgraded to collectibles can be gifted to others later."; "lng_gift_channel_title" = "Send a Gift"; "lng_gift_channel_about" = "Select a gift to show appreciation for {name}."; "lng_gift_released_by" = "released by {name}"; "lng_gift_unique_owner" = "Owner"; "lng_gift_unique_address_copied" = "Address copied to clipboard."; "lng_gift_unique_telegram" = "Telegram"; "lng_gift_unique_status" = "Status"; "lng_gift_unique_status_non" = "Non-Unique"; "lng_gift_unique_upgrade" = "Upgrade"; "lng_gift_unique_upgrade_next" = "Upgrade Next Gift"; "lng_gift_unique_gift_upgrade" = "Gift an Upgrade"; "lng_gift_unique_number" = "Collectible #{index}"; "lng_gift_unique_number_by" = "Collectible #{index} by {name}"; "lng_gift_unique_model" = "Model"; "lng_gift_unique_backdrop" = "Backdrop"; "lng_gift_unique_symbol" = "Symbol"; "lng_gift_unique_rarity" = "Only {percent} of such collectibles have this attribute."; "lng_gift_unique_sender" = "{from} sent you this gift on {date}"; "lng_gift_unique_sender_you" = "You bought this gift on {date}"; "lng_gift_unique_crafter_you" = "You crafted this gift on {date}"; "lng_gift_unique_availability_label" = "Quantity"; "lng_gift_unique_availability#one" = "{count} of {amount} issued"; "lng_gift_unique_availability#other" = "{count} of {amount} issued"; "lng_gift_unique_value" = "Value"; "lng_gift_unique_value_learn_more" = "learn more"; "lng_gift_unique_info" = "Gifted to {recipient} on {date}."; "lng_gift_unique_info_sender" = "Gifted by {from} to {recipient} on {date}."; "lng_gift_unique_info_sender_comment" = "Gifted by {from} to {recipient} on {date} with the comment \"{text}\"."; "lng_gift_unique_info_reciever" = "Gifted to {recipient} on {date}."; "lng_gift_unique_info_reciever_comment" = "Gifted to {recipient} on {date} with the comment \"{text}\"."; "lng_gift_unique_info_remove_title" = "Remove Description"; "lng_gift_unique_info_remove_text" = "Do you want to permanently remove this description from your gift?"; "lng_gift_unique_info_remove_confirm" = "Remove for {cost}"; "lng_gift_unique_info_removed" = "Removed {name}'s Description!"; "lng_gift_availability_left#one" = "{count} of {amount} left"; "lng_gift_availability_left#other" = "{count} of {amount} left"; "lng_gift_availability_none" = "None of {amount} left"; "lng_gift_value_about_average" = "This is the average sale price of {gift} gifts on Telegram and Fragment over the past month."; "lng_gift_value_about_last" = "This is the price at which {gift} was last sold on {platform}."; "lng_gift_value_initial_sale" = "Initial Sale"; "lng_gift_value_initial_price" = "Initial Price"; "lng_gift_value_initial_price_value" = "{stars} ({amount})"; "lng_gift_value_last_sale" = "Last Sale"; "lng_gift_value_last_price" = "Last Price"; "lng_gift_value_minimum_price" = "Minimum Price"; "lng_gift_value_minimum_price_tooltip" = "{amount} is the floor price for {gift} gifts listed on Telegram and Fragment."; "lng_gift_vlaue_average_price" = "Average Price"; "lng_gift_value_average_price_tooltip" = "{amount} is the average sale price of {gift} gifts on Telegram and Fragment over the past month."; "lng_gift_value_availability#one" = "{count} {emoji} for sale on {platform} {arrow}"; "lng_gift_value_availability#other" = "{count} {emoji} for sale on {platform} {arrow}"; "lng_gift_value_telegram" = "Telegram"; "lng_gift_value_fragment" = "Fragment"; "lng_gift_convert_to_stars#one" = "Convert to {count} Star"; "lng_gift_convert_to_stars#other" = "Convert to {count} Stars"; "lng_gift_convert_sure_title" = "Convert Gift to Stars"; "lng_gift_convert_sure_confirm#one" = "Do you want to convert this gift from {user} to **{count} Star**?"; "lng_gift_convert_sure_confirm#other" = "Do you want to convert this gift from {user} to **{count} Stars**?"; "lng_gift_convert_sure_confirm_channel#one" = "Do you want to convert this gift to {channel} to **{count} Star**?"; "lng_gift_convert_sure_confirm_channel#other" = "Do you want to convert this gift to {channel} to **{count} Stars**?"; "lng_gift_convert_sure_limit#one" = "Conversion is available for the next **{count} day**."; "lng_gift_convert_sure_limit#other" = "Conversion is available for the next **{count} days**."; "lng_gift_convert_sure_caution" = "This action cannot be undone. This will permanently destroy the gift."; "lng_gift_convert_sure" = "Convert"; "lng_gift_display_done" = "The gift is now shown on your profile page."; "lng_gift_display_done_channel" = "The gift is now shown in channel's Gifts."; "lng_gift_display_done_hide" = "The gift is now hidden from your profile page."; "lng_gift_display_done_hide_channel" = "The gift is now hidden from channel's Gifts."; "lng_gift_pinned_done_title" = "{gift} pinned"; "lng_gift_pinned_done" = "The gift will always be shown on top."; "lng_gift_pinned_done_replaced" = "replacing {gift}"; "lng_gift_got_stars#one" = "You got **{count} Star** for this gift."; "lng_gift_got_stars#other" = "You got **{count} Stars** for this gift."; "lng_gift_channel_got#one" = "Channel got **{count} Star** for this gift."; "lng_gift_channel_got#other" = "Channel got **{count} Stars** for this gift."; "lng_gift_sold_out_title" = "Sold Out!"; "lng_gift_sold_out_text#one" = "All {count} gift was already sold."; "lng_gift_sold_out_text#other" = "All {count} gifts were already sold."; "lng_gift_send_small" = "send a gift"; "lng_gift_sell_small#one" = "sell for {count} Star"; "lng_gift_sell_small#other" = "sell for {count} Stars"; "lng_gift_upgrade_title" = "Upgrade Gift"; "lng_gift_upgrade_about" = "Turn your gift into a unique collectible\nthat you can transfer or auction."; "lng_gift_upgrade_view_all" = "{emoji} View all variants {arrow}"; "lng_gift_upgrade_preview_title" = "Make Unique"; "lng_gift_upgrade_preview_about" = "Let {name} turn your gift into a unique collectible."; "lng_gift_upgrade_preview_about_channel" = "Let the admins of {name} turn your gift into a unique collectible."; "lng_gift_upgrade_unique_title" = "Unique"; "lng_gift_upgrade_unique_about" = "Get a unique number, model, backdrop and symbol for your gift."; "lng_gift_upgrade_unique_about_user" = "{name} will get a unique number, model, backdrop and symbol for your gift."; "lng_gift_upgrade_unique_about_channel" = "Admins of {name} will get a unique number, model, backdrop and symbol for your gift."; "lng_gift_upgrade_transferable_title" = "Transferable"; "lng_gift_upgrade_transferable_about" = "Send your upgraded gift to any of your friends on Telegram."; "lng_gift_upgrade_transferable_about_user" = "{name} will be able to send the gift to anyone on Telegram."; "lng_gift_upgrade_transferable_about_channel" = "Admins of {name} will be able to send the gift to anyone on Telegram."; "lng_gift_upgrade_tradable_title" = "Tradable"; "lng_gift_upgrade_tradable_about" = "Sell or auction your gift on third-party NFT marketplaces."; "lng_gift_upgrade_tradable_about_user" = "{name} will be able to sell the gift on Telegram and NFT marketplaces."; "lng_gift_upgrade_tradable_about_channel" = "Admins of {name} will be able to sell the gift on Telegram and NFT marketplaces."; "lng_gift_upgrade_wearable_title" = "Wearable"; "lng_gift_upgrade_wearable_about" = "Display gifts on your page and set them as profile covers or statuses."; "lng_gift_upgrade_button" = "Upgrade for {price}"; "lng_gift_upgrade_decreases" = "Price decreases in {time}"; "lng_gift_upgrade_see_table" = "See how this price will decrease {arrow}"; "lng_gift_upgrade_prices_about" = "Upgrade cost drops every minute."; "lng_gift_upgrade_prices_title" = "Upgrade Cost"; "lng_gift_upgrade_prices_subtitle" = "Users who upgrade their gifts first get collectibles with shorter numbers."; "lng_gift_upgrade_free" = "Upgrade for Free"; "lng_gift_upgrade_confirm" = "Confirm"; "lng_gift_upgrade_add_my" = "Add my name to the gift"; "lng_gift_upgrade_add_my_comment" = "Add my name and comment"; "lng_gift_upgrade_add_sender" = "Add sender's name to the gift"; "lng_gift_upgrade_add_comment" = "Add sender's name and comment"; "lng_gift_upgraded_title" = "Gift Upgraded"; "lng_gift_upgraded_about" = "Your gift {name} now has unique attributes and can be transferred to others"; "lng_gift_upgrade_gifted_title" = "Upgrade Gifted"; "lng_gift_upgrade_gifted_about" = "Now {name} can turn your gift into a unique collectible."; "lng_gift_upgrade_gifted_about_channel" = "Now the admins of {name} can turn your gift into a unique collectible."; "lng_gift_transferred_title" = "Gift Transferred"; "lng_gift_transferred_about" = "{name} was successfully transferred to {recipient}."; "lng_gift_transfer_title" = "Transfer {name}"; "lng_gift_transfer_via_blockchain" = "Send via Blockchain"; "lng_gift_transfer_password_title" = "Two-step verification"; "lng_gift_transfer_password_description" = "Please enter your password to transfer."; "lng_gift_transfer_password_about" = "You can withdraw only if you have:"; "lng_gift_transfer_confirm_title" = "Manage with Fragment"; "lng_gift_transfer_confirm_text" = "You can use Fragment, a third-party service, to transfer {name} to your TON account. After that, you can manage it as an NFT with any TON wallet outside Telegram.\n\nYou can also move such NFTs back to your Telegram account via Fragment."; "lng_gift_transfer_confirm_button" = "Open Fragment"; "lng_gift_transfer_unlocks_days#one" = "unlocks in {count} day"; "lng_gift_transfer_unlocks_days#other" = "unlocks in {count} days"; "lng_gift_transfer_unlocks_hours#one" = "unlocks in {count} hour"; "lng_gift_transfer_unlocks_hours#other" = "unlocks in {count} hours"; "lng_gift_transfer_unlocks_title" = "Unlocking in progress"; "lng_gift_transfer_unlocks_about" = "{when}, you'll be able to send this collectible to any TON blockchain address outside Telegram for sale or auction."; "lng_gift_transfer_unlocks_when_days#one" = "In {count} day"; "lng_gift_transfer_unlocks_when_days#other" = "In {count} days"; "lng_gift_transfer_unlocks_when_hours#one" = "In {count} hour"; "lng_gift_transfer_unlocks_when_hours#other" = "In {count} hours"; "lng_gift_transfer_unlocks_update_title" = "Update required"; "lng_gift_transfer_unlocks_update_about" = "Please update your Telegram application to the latest version."; "lng_gift_transfer_sure" = "Do you want to transfer ownership of {name} to {recipient}?"; "lng_gift_transfer_sure_for" = "Do you want to transfer ownership of {name} to {recipient} for {price}?"; "lng_gift_transfer_button" = "Transfer"; "lng_gift_transfer_button_for" = "Transfer for {price}"; "lng_gift_transfer_set_theme" = "Set as Theme in..."; "lng_gift_transfer_choose" = "Choose Chat"; "lng_gift_transfer_wear" = "Wear"; "lng_gift_transfer_take_off" = "Take Off"; "lng_gift_transfer_sell" = "Sell"; "lng_gift_transfer_update" = "Change Price"; "lng_gift_transfer_unlist" = "Unlist"; "lng_gift_transfer_locked_title" = "Action Locked"; "lng_gift_transfer_locked_text" = "Transfer this gift to your Telegram account on Fragment to unlock this action."; "lng_gift_offer_button" = "Offer to Buy"; "lng_gift_offer_title" = "Offer to Buy"; "lng_gift_offer_stars_about" = "Choose how many Stars you'd like to offer for {name}."; "lng_gift_offer_ton_about" = "Choose how many TON you'd like to offer for {name}."; "lng_gift_offer_duration" = "Offer Duration"; "lng_gift_offer_duration_about" = "Choose how long {user} can accept your offer. When the time expires, the amount will be refunded."; "lng_gift_offer_cost_button" = "Offer {cost}"; "lng_gift_offer_reject_title" = "Reject Offer"; "lng_gift_offer_confirm_reject" = "Are you sure you want to reject the offer from {user}?"; "lng_gift_offer_confirm_accept" = "Do you want to sell {name} to {user} for {cost}?"; "lng_gift_offer_you_get" = "You will receive {cost} after fees."; "lng_gift_offer_higher" = "The price you are offered is {percent} higher than the average price for {name}."; "lng_gift_offer_lower" = "The price you are offered is {percent} lower than the average price for {name}."; "lng_gift_offer_sell_for" = "Sell for {price}"; "lng_gift_offer_confirm_title" = "Confirm Offer"; "lng_gift_offer_confirm_text" = "Do you want to offer {cost} to {user} for {name}?"; "lng_gift_offer_table_offer" = "Offer"; "lng_gift_offer_table_fee" = "Fee"; "lng_gift_offer_table_duration" = "Duration"; "lng_gift_sell_unlist_title" = "Unlist {name}"; "lng_gift_sell_unlist_sure" = "Are you sure you want to unlist your gift?"; "lng_gift_sell_title" = "Price in Stars"; "lng_gift_sell_about" = "You will receive {percent} of the selected amount."; "lng_gift_sell_amount#one" = "You will receive **{count}** Star."; "lng_gift_sell_amount#other" = "You will receive **{count}** Stars."; "lng_gift_sell_min_price#one" = "Minimum price is {count} Star."; "lng_gift_sell_min_price#other" = "Minimum price is {count} Stars."; "lng_gift_sell_only_ton" = "Only Accept TON"; "lng_gift_sell_only_ton_about" = "If the buyer pays you in TON, there's no risk of refunds, unlike Stars payments."; "lng_gift_sell_amount_ton#one" = "You will receive **{count}** TON."; "lng_gift_sell_amount_ton#other" = "You will receive **{count}** TON."; "lng_gift_sell_min_price_ton#one" = "Minimum price is {count} TON."; "lng_gift_sell_min_price_ton#other" = "Minimum price is {count} TON."; "lng_gift_sell_title_ton" = "Price in TON"; "lng_gift_sell_put" = "Put for Sale"; "lng_gift_sell_update" = "Update the Price"; "lng_gift_sell_toast" = "{name} is now for sale!"; "lng_gift_sell_updated" = "Sale price for {name} was updated."; "lng_gift_sell_removed" = "{name} is removed from sale."; "lng_gift_menu_show" = "Show"; "lng_gift_menu_hide" = "Hide"; "lng_gift_wear_title" = "Wear {name}"; "lng_gift_wear_about" = "and get these benefits:"; "lng_gift_wear_badge_title" = "Radiant Badge"; "lng_gift_wear_badge_about" = "The glittering icon of this item will be displayed next to your name."; "lng_gift_wear_badge_about_channel" = "The glittering icon of this item will be displayed next to channel's name."; "lng_gift_wear_design_title" = "Unique Profile Design"; "lng_gift_wear_design_about" = "Your profile page will get the color and the symbol of this item."; "lng_gift_wear_design_about_channel" = "Your channel page will get the color and the symbol of this item."; "lng_gift_wear_proof_title" = "Proof of Ownership"; "lng_gift_wear_proof_about" = "Clicking the icon of this item next to your name will show its info and owner."; "lng_gift_wear_proof_about_channel" = "Clicking the icon of this item next to channel's name will show its info and owner."; "lng_gift_wear_start" = "Start Wearing"; "lng_gift_wear_subscribe" = "Subscribe to {link} to wear collectibles."; "lng_gift_wear_start_toast" = "You put on {name}"; "lng_gift_wear_end_toast" = "You took off {name}"; "lng_gift_many_pinned_title" = "Too Many Pinned Gifts"; "lng_gift_many_pinned_choose" = "Select a gift to unpin below"; "lng_gift_resale_price" = "Price"; "lng_gift_resale_number" = "Number"; "lng_gift_resale_date" = "Date"; "lng_gift_resale_count#one" = "{count} gift in resale"; "lng_gift_resale_count#other" = "{count} gifts in resale"; "lng_gift_resale_count_none" = "No listings"; "lng_gift_resale_sort_price" = "Sort by Price"; "lng_gift_resale_sort_date" = "Sort by Date"; "lng_gift_resale_sort_number" = "Sort by Number"; "lng_gift_resale_all_listings" = "All Listings"; "lng_gift_resale_stars_only" = "For Stars Only"; "lng_gift_resale_filter_all" = "Select All"; "lng_gift_resale_model" = "Model"; "lng_gift_resale_models#one" = "{count} Model"; "lng_gift_resale_models#other" = "{count} Models"; "lng_gift_resale_backdrop" = "Backdrop"; "lng_gift_resale_backdrops#one" = "{count} Backdrop"; "lng_gift_resale_backdrops#other" = "{count} Backdrops"; "lng_gift_resale_symbol" = "Symbol"; "lng_gift_resale_symbols#one" = "{count} Symbol"; "lng_gift_resale_symbols#other" = "{count} Symbols"; "lng_gift_resale_search_none" = "No gifts found for your search."; "lng_gift_resale_early" = "You will be able to resell this gift in {duration}."; "lng_gift_transfer_early" = "You will be able to transfer this gift in {duration}."; "lng_gift_resale_transfer_early_title" = "Try Later"; "lng_gift_collection_add" = "Add Collection"; "lng_gift_collection_new_title" = "Create a New Collection"; "lng_gift_collection_new_button" = "New Collection"; "lng_gift_collection_new_text" = "Choose a name for your collection and start adding your gifts there."; "lng_gift_collection_new_ph" = "Title"; "lng_gift_collection_new_create" = "Create"; "lng_gift_collection_empty_title" = "Organize Your Gifts"; "lng_gift_collection_empty_text" = "Add some of your gifts to this collection."; "lng_gift_collection_all" = "All Gifts"; "lng_gift_collection_add_title" = "Add Gifts"; "lng_gift_collection_add_button" = "Add Gifts"; "lng_gift_collection_share" = "Share Collection"; "lng_gift_collection_edit" = "Edit Name"; "lng_gift_collection_limit_title" = "Limit Reached"; "lng_gift_collection_limit_text" = "Please remove one of the existing collections to add a new one."; "lng_gift_collection_delete" = "Delete Collection"; "lng_gift_collection_delete_sure" = "Are you sure you want to delete this collection?"; "lng_gift_collection_delete_button" = "Delete"; "lng_gift_collection_add_to" = "Add to Collection"; "lng_gift_collection_reorder" = "Reorder"; "lng_gift_collection_reorder_exit" = "Apply Reorder"; "lng_gift_collection_remove_from" = "Remove from Collection"; "lng_gift_locked_title" = "Gift Locked"; "lng_gift_craft_menu_button" = "Craft"; "lng_gift_craft_info_title" = "Gift Crafting"; "lng_gift_craft_info_about" = "Turn your gifts into rare, epic\nand legendary versions."; "lng_gift_craft_rare_title" = "Get Rare Models"; "lng_gift_craft_rare_about" = "Select up to 4 gifts to craft a new exclusive model."; "lng_gift_craft_chance_title" = "Maximize Chances"; "lng_gift_craft_chance_about" = "Combine more gifts to increase your odds of success."; "lng_gift_craft_affect_title" = "Affect the Result"; "lng_gift_craft_affect_about" = "Use gifts with the same attribute to boost its chance."; "lng_gift_craft_start_button" = "Start Crafting"; "lng_gift_craft_title" = "Craft Gift"; "lng_gift_craft_about1" = "Add up to **4** gifts to craft new\n{gift}."; "lng_gift_craft_about2" = "If crafting fails, all used gifts\nwill be lost."; "lng_gift_craft_view_all" = "{emoji} View all craftable models {arrow}"; "lng_gift_craft_chance_backdrop" = "{percent} chance the crafted gift will have **{name}** background."; "lng_gift_craft_chance_symbol" = "{percent} chance the crafted gift will have **{name}** symbol."; "lng_gift_craft_button" = "Craft {gift}"; "lng_gift_craft_button_chance" = "{percent} Success Chance"; "lng_gift_craft_select_title" = "Select Gifts"; "lng_gift_craft_select_about" = "You need to add up to **3 gifts** from the same collection for crafting."; "lng_gift_craft_select_your" = "Your gifts"; "lng_gift_craft_select_none" = "You don't have other gifts from this collection."; "lng_gift_craft_search_none" = "Could not find other gifts from this collection."; "lng_gift_craft_select_market#one" = "{count} suitable gift on sale"; "lng_gift_craft_select_market#other" = "{count} suitable gifts on sale"; "lng_gift_craft_progress" = "Crafting"; "lng_gift_craft_progress_about" = "Crafting **{gift}**"; "lng_gift_craft_progress_chance" = "{percent} success chance"; "lng_gift_craft_progress_fails" = "If crafting fails, all used\ngifts will be lost."; "lng_gift_craft_failed" = "Crafting failed. Gifts consumed :("; "lng_gift_craft_failed_title" = "Crafting Failed"; "lng_gift_craft_failed_about#one" = "This crafting attempt was unsuccessful.\n**{count}** gift was lost."; "lng_gift_craft_failed_about#other" = "This crafting attempt was unsuccessful.\n**{count}** gifts were lost."; "lng_gift_craft_new_button" = "Craft New Gift"; "lng_gift_craft_another_button" = "Craft Another Gift"; "lng_gift_craft_unavailable" = "Crafting unavailable"; "lng_gift_craft_when" = "This gift will become available for crafting on {date} at {time}."; "lng_gift_craft_address_error" = "This gift has been exported to the blockchain and can't be used as the primary gift for crafting."; "lng_auction_about_title" = "Auction"; "lng_auction_about_subtitle" = "Join the battle for exclusive gifts."; "lng_auction_about_top_title#one" = "Top {count} Bidder"; "lng_auction_about_top_title#other" = "Top {count} Bidders"; "lng_auction_about_top_rounds#one" = "{count} round"; "lng_auction_about_top_rounds#other" = "{count} rounds"; "lng_auction_about_top_bidders#one" = "top {count} bidder"; "lng_auction_about_top_bidders#other" = "top {count} bidders"; "lng_auction_about_top_about#one" = "{count} gift is dropped in {rounds} to the {bidders} by bid amount."; "lng_auction_about_top_about#other" = "{count} gifts are dropped in {rounds} to the {bidders} by bid amount."; "lng_auction_about_top_short#one" = "{count} gift is dropped to the {bidders} by bid amount. {link}"; "lng_auction_about_top_short#other" = "{count} gifts are dropped to the {bidders} by bid amount. {link}"; "lng_auction_about_bid_title" = "Bid Carryover"; "lng_auction_about_bid_about#one" = "If your bid leaves the top {count}, it will automatically join the next round."; "lng_auction_about_bid_about#other" = "If your bid leaves the top {count}, it will automatically join the next round."; "lng_auction_about_missed_title" = "Missed Bidders"; "lng_auction_about_missed_about" = "If your bid doesn't win after the final round, your Stars will be fully refunded."; "lng_auction_about_understood" = "Understood"; "lng_auction_text#one" = "Top **{count}** bidder will get {name} gifts this round. {link}"; "lng_auction_text#other" = "Top **{count}** bidders will get {name} gifts this round. {link}"; "lng_auction_text_link" = "Learn more {arrow}"; "lng_auction_text_ended" = "Auction ended."; "lng_auction_start_label" = "Started"; "lng_auction_starts_label" = "Starts"; "lng_auction_rounds_label" = "Rounds"; "lng_auction_rounds_exact" = "Round {n}"; "lng_auction_rounds_range" = "Rounds {n}-{last}"; "lng_auction_rounds_seconds#one" = "{count} second each"; "lng_auction_rounds_seconds#other" = "{count} seconds each"; "lng_auction_rounds_minutes#one" = "{count} minute each"; "lng_auction_rounds_minutes#other" = "{count} minutes each"; "lng_auction_rounds_hours#one" = "{count} hour each"; "lng_auction_rounds_hours#other" = "{count} hours each"; "lng_auction_rounds_extended" = "{duration} + {increase} for late bids in top {n}"; "lng_auction_end_label" = "Ends"; "lng_auction_round_label" = "Current Round"; "lng_auction_round_value" = "{n} of {amount}"; "lng_auction_average_label" = "Average Price"; "lng_auction_average_tooltip" = "{amount} is the average sale price for {gift} gifts."; "lng_auction_availability_label" = "Availability"; "lng_auction_availability_value" = "{n} of {amount} left"; "lng_auction_bought#one" = "{count} {emoji} item bought {arrow}"; "lng_auction_bought#other" = "{count} {emoji} items bought {arrow}"; "lng_auction_join_button" = "Join Auction"; "lng_auction_join_bid" = "Place a Bid"; "lng_auction_join_time_left" = "{time} left"; "lng_auction_join_time_medium" = "{hours} h {minutes} m"; "lng_auction_join_time_small" = "{minutes} m"; "lng_auction_join_starts_in" = "starts in {time}"; "lng_auction_join_early_bid" = "Place an Early Bid"; "lng_auction_menu_about" = "About"; "lng_auction_menu_copy_link" = "Copy Link"; "lng_auction_menu_share" = "Share"; "lng_auction_bid_title" = "Place a Bid"; "lng_auction_bid_title_early" = "Place an Early Bid"; "lng_auction_bid_subtitle#one" = "Top {count} bidder will win"; "lng_auction_bid_subtitle#other" = "Top {count} bidders will win"; "lng_auction_bid_your" = "your bid"; "lng_auction_bid_custom" = "click to bid more"; "lng_auction_bid_threshold#one" = "TOP {count}"; "lng_auction_bid_threshold#other" = "TOP {count}"; "lng_auction_bid_minimal#one" = "minimum bid"; "lng_auction_bid_minimal#other" = "minimum bid"; "lng_auction_bid_until" = "until next round"; "lng_auction_bid_left#one" = "left"; "lng_auction_bid_left#other" = "left"; "lng_auction_bid_before_start" = "before start"; "lng_auction_bid_your_title" = "Your bid will be"; "lng_auction_bid_your_outbid" = "You've been outbid"; "lng_auction_bid_your_winning" = "You're winning"; "lng_auction_bid_winners_title" = "Top winners"; "lng_auction_bid_place" = "Place a {stars} Bid"; "lng_auction_bid_increase" = "Add {stars} to Your Bid"; "lng_auction_bid_placed_title" = "Your bid has been placed"; "lng_auction_bid_increased_title" = "Your bid has been increased"; "lng_auction_bid_done_text#one" = "If you fall below the **top {count}**, your bid will roll over to the next round."; "lng_auction_bid_done_text#other" = "If you fall below the **top {count}**, your bid will roll over to the next round."; "lng_auction_bid_custom_title" = "Custom Amount"; "lng_auction_preview_left#one" = "{count} left"; "lng_auction_preview_left#other" = "{count} left"; "lng_auction_preview_join" = "Join"; "lng_auctino_preview_finished" = "Finished"; "lng_auction_preview_sold_out" = "Sold Out"; "lng_auction_preview_view_results" = "View Results"; "lng_auction_bar_active" = "Active Auction"; "lng_auction_bar_active_many#one" = "{count} Active Auction"; "lng_auction_bar_active_many#other" = "{count} Active Auctions"; "lng_auction_bar_winning#one" = "You're winning ({count}st place)."; "lng_auction_bar_winning#other" = "You're winning ({count}th place)."; "lng_auction_bar_outbid" = "You've been outbid."; "lng_auction_bar_winning_all" = "You're winning in all of them."; "lng_auction_bar_outbid_some#one" = "You've been outbid in {count} of them."; "lng_auction_bar_outbid_some#other" = "You've been outbid in {count} of them."; "lng_auction_bar_outbid_all" = "You've been outbid in all of them."; "lng_auction_bar_view" = "View"; "lng_auction_bar_round" = "Round {n} of {amount}"; "lng_auction_bar_bid_ranked" = "Your bid **{stars}** is ranked **#{n}**"; "lng_auction_bar_bid_outbid" = "Your bid **{stars}** is outbid"; "lng_auction_bar_raise_bid" = "Raise Bid"; "lng_auction_bought_title#one" = "{count} Item Bought"; "lng_auction_bought_title#other" = "{count} Items Bought"; "lng_auction_bought_date" = "Date"; "lng_auction_bought_bid" = "Accepted Bid"; "lng_auction_bought_in_round" = "{name} in round {n}"; "lng_auction_change_title" = "Change Recipient"; "lng_auction_change_button" = "Change"; "lng_auction_change_already" = "You've already placed a bid on this gift for {name}."; "lng_auction_change_to" = "Do you want to raise your bid and change the recipient to {name}?"; "lng_auction_change_already_me" = "You've already placed a bid on this gift for yourself."; "lng_auction_change_to_me" = "Do you want to raise your bid and change the recipient to yourself?"; "lng_auction_preview_name" = "Upcoming Auction"; "lng_auction_preview_learn_gifts" = "Learn more about Telegram Gifts {arrow}"; "lng_auction_preview_variants#one" = "View {emoji} {count} Variant {arrow}"; "lng_auction_preview_variants#other" = "View {emoji} {count} Variants {arrow}"; "lng_auction_preview_random" = "Random Traits"; "lng_auction_preview_selected" = "Selected Traits"; "lng_auction_preview_randomize" = "Randomize Traits"; "lng_auction_preview_model" = "model"; "lng_auction_preview_models#one" = "This collectible features **{count}** unique model."; "lng_auction_preview_models#other" = "This collectible features **{count}** unique models."; "lng_auction_preview_models_button" = "Models"; "lng_auction_preview_crafted#one" = "This collectible features **{count}** crafted model."; "lng_auction_preview_crafted#other" = "This collectible features **{count}** crafted models."; "lng_auction_preview_view_craftable" = "View craftable models {arrow}"; "lng_auction_preview_view_primary" = "View primary models {arrow}"; "lng_auction_preview_backdrop" = "backdrop"; "lng_auction_preview_backdrops#one" = "This collectible features **{count}** unique backdrop."; "lng_auction_preview_backdrops#other" = "This collectible features **{count}** unique backdrops."; "lng_auction_preview_backdrops_button" = "Backdrops"; "lng_auction_preview_symbol" = "symbol"; "lng_auction_preview_symbols#one" = "This collectible features **{count}** unique symbol."; "lng_auction_preview_symbols#other" = "This collectible features **{count}** unique symbols."; "lng_auction_preview_symbols_button" = "Symbols"; "lng_auction_preview_wear" = "More about wearing gifts {arrow}"; "lng_auction_preview_free_upgrade" = "You can upgrade your gift for free, sell it on the market, or set it as your profile cover."; "lng_accounts_limit_title" = "Limit Reached"; "lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected account."; "lng_accounts_limit1#other" = "You have reached the limit of **{count}** connected accounts."; "lng_accounts_limit2" = "You can free one place by subscribing to **Telegram Premium** with one of these connected accounts:"; "lng_emoji_status_for_title" = "Set Status for..."; "lng_emoji_status_for_submit" = "Set Status"; "lng_emoji_status_menu_duration_any" = "Set Status for {duration}"; "lng_group_about_header" = "You created a group"; "lng_group_about_text" = "Groups can have:"; "lng_group_about1" = "Up to 200,000 members"; "lng_group_about2" = "Persistent chat history"; "lng_group_about3" = "Public links such as t.me/title"; "lng_group_about4" = "Admins with different rights"; "lng_switch_stickers" = "Stickers"; "lng_switch_emoji" = "Emoji"; "lng_switch_gifs" = "GIFs"; "lng_switch_masks" = "Masks"; "lng_stickers_featured_add" = "Add"; "lng_stickers_featured_installed" = "Added"; "lng_emoji_featured_unlock" = "Unlock"; "lng_emoji_premium_restore" = "Restore"; "lng_gifs_search" = "Search GIFs"; "lng_gifs_no_saved" = "You have no saved GIFs yet."; "lng_inline_bot_no_results" = "No results."; "lng_inline_bot_via" = "via {inline_bot}"; "lng_box_remove" = "Remove"; "lng_stickers_installed_tab" = "Stickers"; "lng_stickers_masks_tab" = "Masks"; "lng_stickers_featured_tab" = "Trending"; "lng_stickers_archived_tab" = "Archived"; "lng_stickers_remove_pack" = "Remove \"{sticker_pack}\"?"; "lng_stickers_add_pack" = "Add stickers"; "lng_stickers_add_masks" = "Add masks"; "lng_stickers_add_emoji" = "Add emoji"; "lng_stickers_share_pack" = "Share Stickers"; "lng_stickers_share_masks" = "Share Masks"; "lng_stickers_share_emoji" = "Share Emoji"; "lng_stickers_not_found" = "Sticker set not found."; "lng_stickers_packs_archived" = "Some of your unused stickers were archived to make room for the sets you activated."; "lng_stickers_copied" = "Link copied to clipboard."; "lng_stickers_copied_emoji" = "Emoji pack link copied to clipboard."; "lng_stickers_default_set" = "Great Minds"; "lng_stickers_you_have" = "Manage sticker sets"; "lng_stickers_return" = "Undo"; "lng_stickers_count#one" = "{count} sticker"; "lng_stickers_count#other" = "{count} stickers"; "lng_masks_count#one" = "{count} mask"; "lng_masks_count#other" = "{count} masks"; "lng_custom_emoji_count#one" = "{count} emoji"; "lng_custom_emoji_count#other" = "{count} emoji"; "lng_stickers_attached_sets" = "Sets of attached stickers"; "lng_custom_emoji_used_sets" = "Sets of used emoji"; "lng_custom_emoji_remove_pack_button" = "Remove Emoji"; "lng_stickers_group_set" = "Group sticker set"; "lng_stickers_remove_group_set" = "Remove group sticker set?"; "lng_stickers_group_from_your" = "Choose from your stickers"; "lng_stickers_group_from_featured" = "Choose from trending stickers"; "lng_stickers_nothing_found" = "No stickers found"; "lng_stickers_remove_pack_confirm" = "Remove"; "lng_stickers_archive_pack" = "Archive Stickers"; "lng_stickers_has_been_archived" = "Sticker set has been archived."; "lng_emoji_group_set" = "Group emoji set"; "lng_emoji_remove_group_set" = "Remove group emoji set?"; "lng_emoji_group_from_your" = "Choose from your emoji"; "lng_emoji_group_from_featured" = "Choose from trending emoji"; "lng_masks_archive_pack" = "Archive Masks"; "lng_masks_has_been_archived" = "Mask pack has been archived."; "lng_masks_installed" = "Mask pack has been installed."; "lng_emoji_nothing_found" = "No emoji found"; "lng_stickers_context_reorder" = "Reorder"; "lng_stickers_context_edit_name" = "Edit name"; "lng_stickers_context_delete" = "Delete sticker"; "lng_stickers_context_delete_sure" = "Are you sure you want to delete the sticker from your sticker set?"; "lng_stickers_box_edit_name_title" = "Edit Sticker Set Name"; "lng_stickers_box_edit_name_about" = "Choose a name for your set."; "lng_stickers_creator_badge" = "edit"; "lng_in_dlg_photo" = "Photo"; "lng_in_dlg_album" = "Album"; "lng_in_dlg_video" = "Video"; "lng_in_dlg_audio_file" = "Audio file"; "lng_in_dlg_contact" = "Contact"; "lng_in_dlg_audio" = "Voice message"; "lng_in_dlg_audio_unread" = "{emoji} Voice message"; "lng_in_dlg_video_message" = "Video message"; "lng_in_dlg_voice_message_ttl" = "One-time Voice Message"; "lng_in_dlg_video_message_ttl" = "One-time Video Message"; "lng_in_dlg_file" = "File"; "lng_in_dlg_sticker" = "Sticker"; "lng_in_dlg_sticker_emoji" = "{emoji} Sticker"; "lng_in_dlg_poll" = "Poll"; "lng_in_dlg_story" = "Story"; "lng_in_dlg_todo_list" = "Checklist"; "lng_in_dlg_story_expired" = "Expired story"; "lng_in_dlg_media_count#one" = "{count} media"; "lng_in_dlg_media_count#other" = "{count} media"; "lng_in_dlg_photo_count#one" = "{count} photo"; "lng_in_dlg_photo_count#other" = "{count} photos"; "lng_in_dlg_video_count#one" = "{count} video"; "lng_in_dlg_video_count#other" = "{count} videos"; "lng_in_dlg_file_count#one" = "{count} file"; "lng_in_dlg_file_count#other" = "{count} files"; "lng_in_dlg_audio_count#one" = "{count} audio"; "lng_in_dlg_audio_count#other" = "{count} audio"; "lng_ban_user" = "Ban User"; "lng_ban_users" = "Ban users"; "lng_restrict_users" = "Restrict users"; "lng_delete_all_from_user" = "Delete all from {user}"; "lng_delete_all_from_users" = "Delete all from users"; "lng_restrict_user#one" = "Restrict user"; "lng_restrict_user#other" = "Restrict users"; "lng_restrict_user_part" = "Partially restrict this user {emoji}"; "lng_restrict_users_part" = "Partially restrict users {emoji}"; "lng_restrict_user_full" = "Fully ban this user {emoji}"; "lng_restrict_users_full" = "Fully ban users {emoji}"; "lng_restrict_users_part_single_header" = "What can this user do?"; "lng_restrict_users_part_header#one" = "What can {count} selected user do?"; "lng_restrict_users_part_header#other" = "What can {count} selected users do?"; "lng_restrict_users_kick_from_common_group" = "Also ban from:"; "lng_report_spam" = "Report Spam"; "lng_report_spam_and_leave" = "Report spam and leave"; "lng_report_spam_done" = "Thank you for your report"; "lng_report_spam_sure_group" = "Are you sure you want to report this group for spam?"; "lng_report_spam_sure_channel" = "Are you sure you want to report spam in this channel?"; "lng_report_spam_ok" = "Report"; "lng_new_contact_block" = "Block user"; "lng_new_contact_block_done" = "{user} is now blocked"; "lng_new_contact_add" = "Add contact"; "lng_new_contact_share" = "Share my phone number"; "lng_new_contact_share_sure" = "Do you want to share your phone number {phone} with {user}?"; "lng_new_contact_share_done" = "{user} can now see your phone number."; "lng_new_contact_add_name" = "Add {user} to contacts"; "lng_new_contact_add_done" = "{user} is now in your contacts"; "lng_new_contact_unarchive" = "Unarchive"; "lng_new_contact_from_request_channel" = "{user} is an admin of {name}, a channel you requested to join."; "lng_new_contact_from_request_group" = "{user} is an admin of {name}, a group you requested to join."; "lng_new_contact_about_status" = "This account uses {emoji} as a custom status next to its\nname. Such emoji statuses are available to all\nsubscribers of {link}."; "lng_new_contact_about_status_link" = "Telegram Premium"; "lng_new_contact_not_contact" = "Not a contact"; "lng_new_contact_phone_number" = "Phone number"; "lng_new_contact_registration" = "Registration"; "lng_new_contact_common_groups" = "Common groups"; "lng_new_contact_groups#one" = "{count} group {emoji} {arrow}"; "lng_new_contact_groups#other" = "{count} groups {emoji} {arrow}"; "lng_new_contact_not_official" = "Not an official account"; "lng_new_contact_updated_name" = "User updated name {when}"; "lng_new_contact_updated_photo" = "User updated photo {when}"; "lng_new_contact_updated_now" = "less than an hour ago"; "lng_new_contact_updated_hours#one" = "{count} hour ago"; "lng_new_contact_updated_hours#other" = "{count} hours ago"; "lng_new_contact_updated_days#one" = "{count} day ago"; "lng_new_contact_updated_days#other" = "{count} days ago"; "lng_new_contact_updated_months#one" = "{count} month ago"; "lng_new_contact_updated_months#other" = "{count} months ago"; "lng_from_request_title_channel" = "Response to your join request"; "lng_from_request_title_group" = "Response to your join request"; "lng_from_request_body" = "You received this message because you requested to join {name} on {date}."; "lng_from_request_understand" = "I understand"; "lng_cant_send_to_not_contact" = "Sorry, you can only send messages to\nmutual contacts at the moment.\n{more_info}"; "lng_cant_invite_not_contact" = "Sorry, you can only add mutual contacts\nto groups at the moment.\n{more_info}"; "lng_cant_more_info" = "Learn more »"; "lng_cant_invite_banned" = "Sorry, only admins can add this user."; "lng_cant_invite_privacy" = "Sorry, you cannot add this user to groups because of their privacy settings."; "lng_cant_invite_bot_to_channel" = "Bots can only be added to channels as admins."; "lng_cant_do_this" = "Sorry, this action is unavailable."; "lng_cant_invite_offer_admin" = "Bots can only be added to channels as admins."; "lng_cant_invite_make_admin" = "Make admin"; "lng_send_button" = "Send"; "lng_schedule_button" = "Schedule"; "lng_send_silent_message" = "Send without sound"; "lng_schedule_message" = "Schedule message"; "lng_reminder_message" = "Set a reminder"; "lng_schedule_title" = "Send this message on..."; "lng_remind_title" = "Remind me on..."; "lng_schedule_repeat_label" = "Repeat:"; "lng_schedule_repeat_never" = "Never"; "lng_schedule_repeat_daily" = "Daily"; "lng_schedule_repeat_weekly" = "Weekly"; "lng_schedule_repeat_biweekly" = "Biweekly"; "lng_schedule_repeat_monthly" = "Monthly"; "lng_schedule_repeat_every_month#one" = "Every {count} month"; "lng_schedule_repeat_every_month#other" = "Every {count} month"; "lng_schedule_repeat_yearly" = "Yearly"; "lng_schedule_repeat_promo" = "Subscribe to {link} to schedule repeating messages."; "lng_schedule_repeat_promo_link" = "Telegram Premium"; "lng_schedule_at" = "at"; "lng_message_ph" = "Write a message..."; "lng_broadcast_ph" = "Broadcast a message..."; "lng_broadcast_silent_ph" = "Silent broadcast..."; "lng_send_anonymous_ph" = "Send anonymously..."; "lng_story_reply_ph" = "Reply privately..."; "lng_story_comment_ph" = "Comment story..."; "lng_video_stream_comment_ph" = "Comment"; "lng_video_stream_comment_paid_ph#one" = "Comment for {count} Star"; "lng_video_stream_comment_paid_ph#other" = "Comment for {count} Stars"; "lng_video_stream_comments_disabled" = "Comments disabled."; "lng_video_stream_stars" = "Add Stars to highlight your comment"; "lng_video_stream_live" = "LIVE"; "lng_video_stream_watched#one" = "{count} watching"; "lng_video_stream_watched#other" = "{count} watching"; "lng_video_stream_edit_stars" = "Edit Stars"; "lng_video_stream_remove_stars" = "Remove Stars"; "lng_message_stars_ph#one" = "Message for {count} Star"; "lng_message_stars_ph#other" = "Message for {count} Stars"; "lng_send_text_no" = "Text not allowed."; "lng_send_text_no_about" = "The admins of this group only allow sending {types}."; "lng_send_text_type_and_last" = "{types} and {last}"; "lng_send_text_type_photos" = "Photos"; "lng_send_text_type_videos" = "Videos"; "lng_send_text_type_video_messages" = "Video Messages"; "lng_send_text_type_music" = "Music"; "lng_send_text_type_voice_messages" = "Voice Messages"; "lng_send_text_type_files" = "Files"; "lng_send_text_type_stickers" = "Stickers & GIFs"; "lng_send_text_type_polls" = "Polls"; "lng_send_gif_with_caption" = "Send GIF with caption"; "lng_send_as_title" = "Send message as..."; "lng_send_as_anonymous_admin" = "Anonymous admin"; "lng_send_as_premium_required" = "Subscribe to {link} to be able to comment on behalf of your channels in group chats."; "lng_send_as_premium_required_link" = "Telegram Premium"; "lng_record_cancel" = "Release outside this field to cancel"; "lng_record_cancel_stories" = "Release outside to cancel"; "lng_record_lock_cancel_sure" = "Do you want to stop recording and discard your voice message?"; "lng_record_lock_cancel_sure_round" = "Do you want to stop recording and discard your video message?"; "lng_record_listen_cancel_sure" = "Do you want to discard your recorded voice message?"; "lng_record_listen_cancel_sure_round" = "Do you want to discard your recorded video message?"; "lng_record_lock_discard" = "Discard"; "lng_record_lock" = "Lock recording"; "lng_record_lock_resume" = "Resume recording"; "lng_record_lock_delete" = "Delete recording"; "lng_record_lock_play" = "Play recording"; "lng_record_lock_pause" = "Pause recording"; "lng_record_cancel_recording" = "Cancel recording"; "lng_record_hold_tip" = "Please hold the mouse button pressed to record a voice message."; "lng_record_voice_tip" = "Hold to record audio. Click to switch to video."; "lng_record_video_tip" = "Hold to record video. Click to switch to audio."; "lng_record_audio_problem" = "Could not start audio recording. Please check your microphone."; "lng_record_video_problem" = "Could not start video recording. Please check your camera."; "lng_record_once_first_tooltip" = "Click to set this message to **Play Once**."; "lng_record_once_active_tooltip" = "The recipient will be able to listen only once."; "lng_record_once_active_video" = "The recipient will be able to watch only once."; "lng_will_be_notified" = "Subscribers will be notified when you post."; "lng_wont_be_notified" = "Subscribers will receive a silent notification."; "lng_willbe_history" = "Select a chat to start messaging"; "lng_from_you" = "You"; "lng_from_draft" = "Draft"; "lng_bot_description" = "What can this bot do?"; "lng_unblock_button" = "Unblock"; "lng_restart_button" = "Restart"; "lng_channel_mute" = "Mute"; "lng_channel_unmute" = "Unmute"; "lng_saved_messages" = "Saved Messages"; "lng_saved_short" = "Save"; "lng_saved_forward_here" = "Forward messages here for quick access"; "lng_saved_quote_here" = "Quote here to save"; "lng_saved_open_chat" = "Open Chat"; "lng_saved_open_channel" = "Open Channel"; "lng_saved_open_group" = "Open Group"; "lng_saved_about_hidden" = "Senders of these messages restricted to link their name when forwarding."; "lng_scheduled_messages" = "Scheduled Messages"; "lng_scheduled_messages_empty" = "No scheduled messages here yet..."; "lng_reminder_messages" = "Reminders"; "lng_scheduled_date" = "Scheduled for {date}"; "lng_scheduled_date_until_online" = "Scheduled until online"; "lng_scheduled_send_until_online" = "Send when online"; "lng_scheduled_send_now" = "Send message now?"; "lng_scheduled_send_now_many#one" = "Send {count} message now?"; "lng_scheduled_send_now_many#other" = "Send {count} messages now?"; "lng_scheduled_video_tip_title" = "Improving video..."; "lng_scheduled_video_tip_text" = "The video will be published after it's optimized for the best viewing experience."; "lng_scheduled_video_tip" = "Processing video may take a few minutes."; "lng_scheduled_video_published" = "Video Published."; "lng_scheduled_video_view" = "View"; "lng_replies_view#one" = "View {count} Reply"; "lng_replies_view#other" = "View {count} Replies"; "lng_replies_view_thread" = "View Thread"; "lng_replies_header#one" = "{count} reply"; "lng_replies_header#other" = "{count} replies"; "lng_replies_header_none" = "Replies"; "lng_replies_view_topic" = "View in Topic"; "lng_comments_header#one" = "{count} comment"; "lng_comments_header#other" = "{count} comments"; "lng_comments_header_none" = "Comments"; "lng_comments_open_count#one" = "{count} comment"; "lng_comments_open_count#other" = "{count} comments"; "lng_comments_open_none" = "Leave a comment"; "lng_replies_view_original" = "View in chat"; "lng_replies_messages" = "Replies"; "lng_hidden_author_messages" = "Author Hidden"; "lng_my_notes" = "My Notes"; "lng_replies_discussion_started" = "Discussion started"; "lng_replies_no_comments" = "No comments here yet..."; "lng_verification_codes" = "Verification Codes"; "lng_verification_codes_about" = "Third-party services, like websites and stores, can send verification codes to your phone number via Telegram instead of SMS. Such codes will appear in this chat.\n\nIf you didn't request any codes — don't worry! Most likely, someone made a mistake when entering their number."; "lng_archived_name" = "Archived chats"; "lng_archived_add" = "Archive"; "lng_archived_remove" = "Unarchive"; "lng_archived_added" = "Chat archived.\nMuted chats stay archived when new messages arrive."; "lng_archived_removed" = "Chat restored from your archive."; "lng_archived_last_list" = "{accumulated}, {chat}"; "lng_archived_last#one" = "{chats} and {count} more chat"; "lng_archived_last#other" = "{chats} and {count} more chats"; "lng_dialogs_text_with_from" = "{from_part} {message}"; "lng_dialogs_text_from_wrapped" = "{from}:"; "lng_dialogs_text_media" = "{media_part} {caption}"; "lng_dialogs_text_media_wrapped" = "{media},"; "lng_dialogs_text_from_in_topic" = "{from} {topic}"; "lng_dialogs_skip_archive_in_search" = "Skip results from archive"; "lng_dialogs_show_archive_in_search" = "With results from archive"; "lng_dialogs_suggestions_birthday_title" = "Add your birthday! 🎂"; "lng_dialogs_suggestions_birthday_about" = "Let your contacts know when you’re celebrating."; "lng_dialogs_suggestions_birthday_contact_title" = "It’s {text}'s **birthday** today! 🎂"; "lng_dialogs_suggestions_birthday_contact_about" = "Send them a Gift."; "lng_dialogs_suggestions_birthday_contacts_title#one" = "{count} contact have **birthdays** today! 🎂"; "lng_dialogs_suggestions_birthday_contacts_title#other" = "{count} contacts have **birthdays** today! 🎂"; "lng_dialogs_suggestions_birthday_contacts_about" = "Send them a Gift."; "lng_dialogs_suggestions_birthday_contact_dismiss" = "You can send a Gift later in Settings"; "lng_dialogs_suggestions_premium_annual_title" = "Telegram Premium with a {text} discount"; "lng_dialogs_suggestions_premium_annual_about" = "Sign up for the annual payment plan for Telegram Premium now to get the discount."; "lng_dialogs_suggestions_premium_upgrade_title" = "Telegram Premium with a {text} discount"; "lng_dialogs_suggestions_premium_upgrade_about" = "Upgrade to the annual payment plan for Telegram Premium now to get the discount."; "lng_dialogs_suggestions_premium_restore_title" = "Get Premium back with up to {text} off"; "lng_dialogs_suggestions_premium_restore_about" = "Your Telegram Premium has recently expired. Tap here to extend it."; "lng_dialogs_suggestions_premium_grace_title" = "⚠️ Your Premium subscription is expiring!"; "lng_dialogs_suggestions_premium_grace_about" = "Don’t lose access to exclusive features."; "lng_dialogs_suggestions_userpics_title" = "Add your photo! 📸"; "lng_dialogs_suggestions_userpics_about" = "Help your friends spot you easily."; "lng_dialogs_suggestions_credits_sub_low_title#one" = "{emoji} {count} Star needed for {channels}"; "lng_dialogs_suggestions_credits_sub_low_title#other" = "{emoji} {count} Stars needed for {channels}"; "lng_dialogs_suggestions_credits_sub_low_about" = "Insufficient funds to cover your subscription."; "lng_unconfirmed_auth_title" = "Someone just got access to your messages!"; "lng_unconfirmed_auth_confirm" = "Yes, it’s me"; "lng_unconfirmed_auth_deny" = "No, it’s not me!"; "lng_unconfirmed_auth_single" = "We detected a new login to your account from {from}, {country}. Is it you?"; "lng_unconfirmed_auth_multiple#one" = "We detected new {count} login to your account. Is it you?"; "lng_unconfirmed_auth_multiple#other" = "We detected new {count} logins to your account. Is it you?"; "lng_unconfirmed_auth_multiple_from#one" = "We detected new {count} login to your account from {country}. Is it you?"; "lng_unconfirmed_auth_multiple_from#other" = "We detected new {count} logins to your account from {country}. Is it you?"; "lng_unconfirmed_auth_denied_title#one" = "New Login Prevented"; "lng_unconfirmed_auth_denied_title#other" = "New Logins Prevented"; "lng_unconfirmed_auth_denied_single" = "We have terminated the login attempt from {country}."; "lng_unconfirmed_auth_denied_multiple" = "We have terminated the login attempts from: {country}"; "lng_unconfirmed_auth_denied_warning" = "Never send your login code to anyone or you can lose your Telegram account!"; "lng_unconfirmed_auth_confirmed" = "New Login Allowed"; "lng_unconfirmed_auth_confirmed_message" = "You can check the list of your active logins in {link}."; "lng_about_random" = "Send a {emoji} emoji to any chat to try your luck."; "lng_about_random_send" = "Send"; "lng_about_random_stake" = "Stake: {amount}"; "lng_about_random_stake_change" = "change"; "lng_open_this_link" = "Open this link?"; "lng_open_link" = "Open"; "lng_allow_bot_pass" = "Allow {bot_name} to pass your Telegram name and ID (not your phone number) to the web pages you open via this bot?"; "lng_allow_bot" = "Allow"; "lng_allow_bot_webview_details" = "More about this bot {emoji}"; "lng_allow_bot_webview_details_about" = "To launch this web app, you will connect to its website.\n\nIt will be able to access your **IP address** and basic device info."; "lng_url_auth_open_confirm" = "Do you want to open {link}?"; "lng_url_auth_login_option" = "Log in to {domain} as {user}"; "lng_url_auth_allow_messages" = "Allow {bot} to send me messages"; "lng_url_auth_login_title" = "Log in to {domain}"; "lng_url_auth_login_button" = "Log in"; "lng_url_auth_site_access" = "This site will receive your **name**, **username** and **profile photo**."; "lng_url_auth_app_access" = "This app will receive your **name**, **username** and **profile photo**."; "lng_url_auth_unverified_app" = "Unverified App"; "lng_url_auth_device_label" = "Device"; "lng_url_auth_ip_label" = "IP Address"; "lng_url_auth_login_attempt" = "This login attempt came from the device above."; "lng_url_auth_allow_messages_label" = "Allow Messages"; "lng_url_auth_allow_messages_about" = "This will allow {bot} to message you"; "lng_url_auth_phone_sure_title" = "Phone Number"; "lng_url_auth_phone_sure_text" = "{domain} wants to access your phone number **{phone}**.\n\nAllow access?"; "lng_url_auth_phone_sure_deny" = "Deny"; "lng_url_auth_phone_toast_good_title" = "Login successful"; "lng_url_auth_phone_toast_good" = "You're now logged in to {domain}."; "lng_url_auth_phone_toast_good_no_phone" = "You're now logged in to {domain}, but you didn't grant access to your phone number."; "lng_url_auth_phone_toast_bad_title" = "Login failed"; "lng_url_auth_phone_toast_bad" = "Please try logging in to {domain} again."; "lng_url_auth_phone_toast_bad_expired" = "This link is expired."; "lng_url_auth_match_code_title" = "Tap the emoji shown on your other device"; "lng_url_auth_match_code_info" = "Login request from {domain}"; "lng_bot_start" = "Start"; "lng_bot_choose_group" = "Select a Group"; "lng_bot_no_groups" = "You have no groups"; "lng_bot_groups_not_found" = "No groups found"; "lng_bot_sure_invite" = "Add the bot to «{group}»?"; "lng_bot_already_in_group" = "The bot is already a member of the group."; "lng_bot_choose_chat" = "Select a chat"; "lng_bot_no_chats" = "You have no chats"; "lng_bot_chats_not_found" = "No chats found"; "lng_bot_sure_share_game" = "Share the game with {user}?"; "lng_bot_sure_share_game_group" = "Share the game with «{group}»?"; "lng_bot_groups_manage" = "Groups I manage"; "lng_bot_channels_manage" = "Channels I manage"; "lng_bot_groups" = "Groups"; "lng_bot_add_title" = "Add Bot"; "lng_bot_as_admin_check" = "Admin rights"; "lng_bot_add_as_admin" = "Add Bot as Admin"; "lng_bot_add_as_member" = "Add Bot as Member"; "lng_bot_sure_add_text_group" = "Are you sure you want to add this bot as an admin in the group {group}? It will have access to the list of anonymous admins."; "lng_bot_sure_add_text_channel" = "Are you sure you want to add this bot as an admin in the channel {group}? It will have access to lists of channel admins and subscribers."; "lng_bot_no_webview" = "Unfortunately, you can't open this menu with your current system configuration."; "lng_bot_remove_from_menu" = "Remove from menu"; "lng_bot_remove_from_menu_sure" = "Remove {bot} from the attachment menu?"; "lng_bot_remove_from_menu_done" = "Bot removed from the menu."; "lng_bot_remove_from_side_menu" = "Remove From Menu"; "lng_bot_remove_from_side_menu_sure" = "Remove {bot} from the main menu?"; "lng_bot_remove_from_side_menu_done" = "Bot removed from the main menu."; "lng_bot_settings" = "Settings"; "lng_bot_open" = "Open Bot"; "lng_bot_terms" = "Terms of Use"; "lng_bot_privacy" = "Privacy Policy"; "lng_bot_reload_page" = "Reload Page"; "lng_bot_add_to_menu" = "{bot} asks your permission to be added as an option to your attachment menu so you can access it from any chat."; "lng_bot_add_to_menu_done" = "Bot added to the menu."; "lng_bot_will_be_added" = "{bot} shortcuts will be added to the attachment menu and the main menu."; "lng_bot_side_menu_new" = "NEW"; "lng_bot_menu_not_supported" = "This bot can't be added to the attachment menu."; "lng_bot_menu_already_added" = "This bot is already added to your attachment menu."; "lng_bot_menu_button" = "Menu"; "lng_bot_close_warning_title" = "Warning"; "lng_bot_close_warning" = "Changes that you made may not be saved."; "lng_bot_close_warning_sure" = "Close anyway"; "lng_bot_add_to_side_menu" = "{bot} asks your permission to be added as an option to your main menu so you can access it any time."; "lng_bot_add_to_side_menu_done" = "Bot added to the main menu."; "lng_bot_no_scan_qr" = "QR Codes for bots are not supported on Desktop. Please use one of Telegram's mobile apps."; "lng_bot_no_share_story" = "Sharing to Stories is not supported on Desktop. Please use one of Telegram's mobile apps."; "lng_bot_emoji_status_confirm" = "Confirm"; "lng_bot_emoji_status_title" = "Set Emoji Status"; "lng_bot_emoji_status_text" = "Do you want to set this emoji status suggested by {bot}?"; "lng_bot_emoji_status_access_text" = "{bot} requests access to set your **emoji status**. You will be able to revoke this access in the profile page of {name}."; "lng_bot_emoji_status_access_allow" = "Allow"; "lng_bot_share_prepared_title" = "Share Message"; "lng_bot_share_prepared_about" = "{bot} mini app suggests you to send this message to a chat you select."; "lng_bot_share_prepared_button" = "Share With..."; "lng_bot_download_file" = "Download File"; "lng_bot_download_file_sure" = "{bot} suggests you download the following file:"; "lng_bot_download_file_button" = "Download"; "lng_bot_download_starting" = "Starting..."; "lng_bot_download_failed" = "Failed. {retry}"; "lng_bot_download_retry" = "Retry"; "lng_bot_status_users#one" = "{count} monthly user"; "lng_bot_status_users#other" = "{count} monthly users"; "lng_typing" = "typing"; "lng_user_typing" = "{user} is typing"; "lng_users_typing" = "{user} and {second_user} are typing"; "lng_many_typing#one" = "{count} person is typing"; "lng_many_typing#other" = "{count} people are typing"; "lng_playing_game" = "playing a game"; "lng_user_playing_game" = "{user} is playing a game"; "lng_users_playing_game" = "{user} and {second_user} are playing a game"; "lng_many_playing_game#one" = "{count} person is playing a game"; "lng_many_playing_game#other" = "{count} people are playing a game"; "lng_send_action_record_video" = "recording a video"; "lng_user_action_record_video" = "{user} is recording a video"; "lng_send_action_upload_video" = "sending a video"; "lng_user_action_upload_video" = "{user} is sending a video"; "lng_send_action_record_audio" = "recording a voice message"; "lng_user_action_record_audio" = "{user} is recording a voice message"; "lng_send_action_upload_audio" = "sending a voice message"; "lng_user_action_upload_audio" = "{user} is sending a voice message"; "lng_send_action_record_round" = "recording a video message"; "lng_user_action_record_round" = "{user} is recording a video message"; "lng_send_action_upload_round" = "sending a video message"; "lng_user_action_upload_round" = "{user} is sending a video message"; "lng_send_action_upload_photo" = "sending a photo"; "lng_user_action_upload_photo" = "{user} is sending a photo"; "lng_send_action_upload_file" = "sending a file"; "lng_user_action_upload_file" = "{user} is sending a file"; "lng_send_action_choose_sticker" = "choosing a sticker"; "lng_user_action_choose_sticker" = "{user} is choosing a sticker"; "lng_user_action_watching_animations" = "watching {emoji}"; "lng_unread_bar#one" = "{count} Unread Message"; "lng_unread_bar#other" = "{count} Unread Messages"; "lng_unread_bar_some" = "Unread messages"; "lng_maps_point" = "Location"; "lng_maps_select_on_map" = "Select on the Map"; "lng_maps_point_send" = "Send This Location"; "lng_maps_point_set" = "Set This Location"; "lng_maps_or_choose" = "Or choose a venue"; "lng_maps_places_in_area" = "Places in this area"; "lng_maps_no_places" = "No places found"; "lng_maps_choose_to_search" = "Choose location to see places nearby."; "lng_maps_venues_source" = "Powered by Foursquare"; "lng_live_location" = "Live Location"; "lng_live_location_now" = "updated just now"; "lng_live_location_minutes#one" = "updated {count} minute ago"; "lng_live_location_minutes#other" = "updated {count} minutes ago"; "lng_live_location_hours#one" = "updated {count} hour ago"; "lng_live_location_hours#other" = "updated {count} hours ago"; "lng_live_location_today" = "updated today at {time}"; "lng_live_location_yesterday" = "updated yesterday at {time}"; "lng_live_location_date_time" = "updated {date} at {time}"; "lng_save_photo" = "Save Image"; "lng_save_video" = "Save Video"; "lng_save_audio_file" = "Save Audio File"; "lng_save_audio" = "Save voice message"; "lng_save_file" = "Save File"; "lng_save_downloaded" = "{ready} / {total} {mb}"; "lng_duration_and_size" = "{duration}, {size}"; "lng_duration_played" = "{played} / {duration}"; "lng_date_and_duration" = "{date}, {duration}"; "lng_choose_image" = "Choose an image"; "lng_choose_file" = "Choose a file"; "lng_choose_files" = "Choose Files"; "lng_choose_cover" = "Choose video cover"; "lng_choose_cover_bad" = "Can't use this file as a caption."; "lng_game_tag" = "Game"; "lng_context_new_window" = "Open in new window"; "lng_context_view_profile" = "View profile"; "lng_context_send_message" = "Send message"; "lng_context_view_group" = "View group info"; "lng_context_view_channel" = "View channel info"; "lng_context_view_topic" = "View topic info"; "lng_context_view_thread" = "View thread info"; "lng_context_hide_psa" = "Hide this announcement"; "lng_context_pin_to_top" = "Pin"; "lng_context_unpin_from_top" = "Unpin"; "lng_context_mark_unread" = "Mark as unread"; "lng_context_mark_read" = "Mark as read"; "lng_context_mark_read_sure" = "Are you sure you want to mark all chats from this folder as read?"; "lng_context_mark_read_all" = "Mark all chats as read"; "lng_context_mark_read_all_sure" = "Are you sure you want to mark all chats as read?"; "lng_context_mark_read_all_sure_2" = "**This action cannot be undone.**"; "lng_context_mark_read_mentions_all" = "Mark all mentions as read"; "lng_context_mark_read_reactions_all" = "Read all reactions"; "lng_context_mark_read_poll_votes_all" = "Read all poll votes"; "lng_context_archive_expand" = "Expand"; "lng_context_archive_collapse" = "Collapse"; "lng_context_archive_to_menu" = "Move to main menu"; "lng_context_archive_to_list" = "Move to chat list"; "lng_context_archive_to_menu_info" = "Archive moved to the main menu!\nRight click the archive button to return the Archive to your chat list."; "lng_context_archive_settings" = "Archive settings"; "lng_context_archive_how_does_it_work" = "How does it work?"; "lng_context_mute" = "Mute notifications"; "lng_context_unmute" = "Unmute"; "lng_context_promote_admin" = "Promote to admin"; "lng_context_edit_permissions" = "Edit admin rights"; "lng_context_restrict_user" = "Restrict user"; "lng_context_ban_user" = "Ban"; "lng_context_delete_and_ban" = "Delete and ban"; "lng_context_remove_from_group" = "Remove from group"; "lng_context_add_to_group" = "Add to group"; "lng_context_rate_transcription" = "Rate transcription"; "lng_toast_sent_rate_transcription" = "Thank you for your feedback!"; "lng_context_copy_link" = "Copy Link"; "lng_context_copy_message_link" = "Copy Message Link"; "lng_context_copy_post_link" = "Copy Post Link"; "lng_context_copy_topic_link" = "Copy Topic Link"; "lng_context_copy_email" = "Copy Email Address"; "lng_context_copy_hashtag" = "Copy Hashtag"; "lng_context_copy_mention" = "Copy Username"; "lng_context_copy_filename" = "Copy Filename"; "lng_context_save_image" = "Save As..."; "lng_context_copy_image" = "Copy Image"; "lng_context_cancel_download" = "Cancel Download"; "lng_context_show_in_folder" = "Show in Folder"; "lng_context_show_in_finder" = "Show in Finder"; "lng_context_save_video" = "Save As..."; "lng_context_save_audio_file" = "Save As..."; "lng_context_save_audio" = "Save As..."; "lng_context_pack_info" = "View Sticker Set"; "lng_context_pack_add" = "Add Stickers"; "lng_context_save_file" = "Save As..."; "lng_context_save_music_to" = "Save to..."; "lng_context_save_music_profile" = "... Profile"; "lng_context_save_music_saved" = "... Saved Messages"; "lng_context_save_music_folder" = "... Downloads"; "lng_context_save_music_about" = "Choose where you want this audio to be saved."; "lng_context_copy_text" = "Copy Text"; "lng_context_open_gif" = "Open GIF"; "lng_context_save_gif" = "Add to GIFs"; "lng_context_delete_gif" = "Delete"; "lng_context_open_channel" = "Open Channel"; "lng_context_open_group" = "Open Group"; "lng_context_attached_stickers" = "Attached Stickers"; "lng_context_to_msg" = "Go To Message"; "lng_context_reply_msg" = "Reply"; "lng_context_quote_and_reply" = "Quote & Reply"; "lng_context_reply_with_timecode" = "Reply with timecode"; "lng_context_reply_to_task" = "Reply to Task"; "lng_context_reply_to_poll_option" = "Reply to Option"; "lng_context_copy_poll_option" = "Copy Option"; "lng_context_copy_poll_option_link" = "Copy Option Link"; "lng_context_delete_poll_option" = "Delete Item"; "lng_context_poll_message_tab" = "Poll"; "lng_context_poll_option_tab" = "Option"; "lng_context_edit_msg" = "Edit"; "lng_context_draw" = "Edit Image"; "lng_context_add_factcheck" = "Add Fact Check"; "lng_context_edit_factcheck" = "Edit Fact Check"; "lng_context_add_offer" = "Add Offer"; "lng_context_forward_msg" = "Forward"; "lng_context_send_now_msg" = "Send Now"; "lng_context_reschedule" = "Reschedule"; "lng_context_delete_msg" = "Delete"; "lng_context_auto_delete_in" = "auto-deletes in {duration}"; "lng_context_select_msg" = "Select"; "lng_context_select_msg_bulk" = "Select up to this message"; "lng_context_report_msg" = "Report"; "lng_context_pin_msg" = "Pin"; "lng_context_unpin_msg" = "Unpin"; "lng_context_cancel_upload" = "Cancel Upload"; "lng_context_upload_edit_caption" = "Edit Caption"; "lng_context_copy_selected" = "Copy Selected Text"; "lng_context_copy_selected_items" = "Copy Selected as Text"; "lng_context_forward_selected" = "Forward Selected"; "lng_context_send_now_selected" = "Send selected now"; "lng_context_reschedule_selected" = "Reschedule Selected"; "lng_context_delete_selected" = "Delete Selected"; "lng_context_save_images_selected" = "Save Selected"; "lng_context_save_documents_selected" = "Download Selected"; "lng_context_clear_selection" = "Clear Selection"; "lng_context_to_save_messages" = "To Saved Messages"; "lng_context_group_items" = "Group Selected"; "lng_context_seen_loading" = "Loading..."; "lng_context_seen_text#one" = "{count} Seen"; "lng_context_seen_text#other" = "{count} Seen"; "lng_context_seen_text_none" = "Nobody Viewed"; "lng_context_seen_listened#one" = "{count} Listened"; "lng_context_seen_listened#other" = "{count} Listened"; "lng_context_seen_listened_none" = "Nobody Listened"; "lng_context_seen_watched#one" = "{count} Listened"; "lng_context_seen_watched#other" = "{count} Listened"; "lng_context_seen_watched_none" = "Nobody Listened"; "lng_context_seen_reacted#one" = "{count} Reacted"; "lng_context_seen_reacted#other" = "{count} Reacted"; "lng_context_seen_reactions_count#one" = "{count} Reaction"; "lng_context_seen_reactions_count#other" = "{count} Reactions"; "lng_context_seen_reacted_none" = "Nobody Reacted"; "lng_context_seen_reacted_all" = "Show All Reactions"; "lng_context_sent_by" = "Sent by {user}"; "lng_context_sent_today" = "Sent today at {time}"; "lng_context_sent_yesterday" = "Sent yesterday at {time}"; "lng_context_sent_date" = "Sent {date} at {time}"; "lng_context_set_as_quick" = "Set As Quick"; "lng_context_filter_by_tag" = "Filter by Tag"; "lng_context_tag_add_name" = "Add Name"; "lng_context_tag_edit_name" = "Edit Name"; "lng_context_remove_tag" = "Remove Tag"; "lng_context_delete_from_disk" = "Delete from disk"; "lng_context_delete_all_files" = "Delete all files"; "lng_context_save_custom_sound" = "Save for Notifications"; "lng_context_translate" = "Translate"; "lng_context_translate_selected" = "Translate Selected Text"; "lng_context_read_hidden" = "read"; "lng_context_read_show" = "show when"; "lng_context_edit_shortcut" = "Edit Shortcut"; "lng_context_delete_shortcut" = "Delete Quick Reply"; "lng_context_gift_send" = "Send Another Gift"; "lng_context_charge_fee" = "Charge Fee"; "lng_context_remove_fee" = "Remove Fee"; "lng_context_fee_now" = "{name} pays {amount} per message."; "lng_context_fee_free" = "{name} can send messages for free."; "lng_add_tag_about" = "Tag this message with an emoji for quick search."; "lng_subscribe_tag_about" = "Organize your Saved Messages with tags. {link}"; "lng_subscribe_tag_link" = "Learn More..."; "lng_edit_tag_about" = "You can label your emoji tag with a text name."; "lng_edit_tag_name" = "Name"; "lng_add_tag_button" = "Add tags"; "lng_add_tag_phrase" = "to messages {arrow}"; "lng_add_tag_phrase_long" = "to your Saved Messages {arrow}"; "lng_unlock_tags" = "Unlock"; "lng_add_tag_selector#one" = "You can add a tag to the message"; "lng_add_tag_selector#other" = "You can add a tag to the messages"; "lng_message_tagged_with" = "Message tagged with {emoji}"; "lng_tagged_view_saved" = "View"; "lng_add_channel_to_filter_selector" = "You can add a channel to your folder"; "lng_add_group_to_filter_selector" = "You can add a group to your folder"; "lng_context_animated_emoji" = "This message contains emoji from **{name} pack**."; "lng_context_animated_emoji_many#one" = "This message contains emoji from **{count} pack**."; "lng_context_animated_emoji_many#other" = "This message contains emoji from **{count} packs**."; "lng_context_animated_reaction" = "This reaction is from the **{name}** pack."; "lng_context_animated_emoji_preview" = "This emoji is from the **{name}** pack."; "lng_context_animated_tag" = "This tag is from **{name} pack**."; "lng_context_animated_reactions" = "Reactions contain emoji from **{name} pack**."; "lng_context_animated_reactions_many#one" = "Reactions contain emoji from **{count} pack**."; "lng_context_animated_reactions_many#other" = "Reactions contain emoji from **{count} packs**."; "lng_context_animated_poll_option" = "This option contains emoji from **{name} pack**."; "lng_context_animated_poll_option_many#one" = "This option contains emoji from **{count} pack**."; "lng_context_animated_poll_option_many#other" = "This option contains emoji from **{count} packs**."; "lng_context_noforwards_info_channel" = "Copying and forwarding is not allowed in this channel."; "lng_context_noforwards_info_group" = "Copying and forwarding is not allowed in this group."; "lng_context_noforwards_info_bot" = "Copying and forwarding is not allowed from this bot."; "lng_context_noforwards_info_his" = "{user} disabled copying and forwarding in this chat."; "lng_context_noforwards_info_mine" = "You disabled copying and forwarding in this chat."; "lng_context_spoiler_effect" = "Hide with Spoiler"; "lng_context_make_paid" = "Make This Content Paid"; "lng_context_change_price" = "Change Price"; "lng_context_edit_cover" = "Edit Cover"; "lng_context_clear_cover" = "Clear Cover"; "lng_context_mention" = "Mention"; "lng_context_search_from" = "Search messages"; "lng_factcheck_title" = "Fact Check"; "lng_factcheck_placeholder" = "Add Facts or Context"; "lng_factcheck_whats_this" = "what's this?"; "lng_factcheck_about" = "This clarification was provided by a fact checking agency assigned by the department of the government of your country ({country}) responsible for combatting misinformation."; "lng_factcheck_add_done" = "Fact check added."; "lng_factcheck_edit_done" = "Fact check edited."; "lng_factcheck_remove_done" = "Fact check removed."; "lng_factcheck_bottom" = "This clarification was provided by a fact checking agency assigned by the department of the government of your country ({country}) responsible for combatting misinformation."; "lng_factcheck_links" = "Only **t.me/** links are allowed."; "lng_paid_title" = "Paid Content"; "lng_paid_enter_cost" = "Enter Unlock Cost"; "lng_paid_cost_placeholder" = "Stars to Unlock"; "lng_paid_about" = "Users will have to transfer this amount of Stars to your channel in order to view this media. {link}"; "lng_paid_about_link" = "More about stars >"; "lng_paid_about_link_url" = "https://telegram.org/blog/telegram-stars"; "lng_paid_price" = "Unlock for {price}"; "lng_paid_react_title" = "Star Reaction"; "lng_paid_react_about" = "Choose how many **Stars** you want to send to {channel} to support this post."; "lng_paid_react_already#one" = "You sent **{count} Star** to support this post."; "lng_paid_react_already#other" = "You sent **{count} Stars** to support this post."; "lng_paid_react_top_title" = "Top Senders"; "lng_paid_react_send" = "Send {price}"; "lng_paid_react_agree" = "By sending stars, you agree to the {link}."; "lng_paid_react_agree_link" = "Terms of Service"; "lng_paid_react_admin_cant" = "You can't send Stars to your own Live Story."; "lng_paid_react_toast#one" = "Star Sent!"; "lng_paid_react_toast#other" = "Stars Sent!"; "lng_paid_react_toast_anonymous#one" = "Star sent anonymously!"; "lng_paid_react_toast_anonymous#other" = "Stars sent anonymously!"; "lng_paid_react_toast_text#one" = "You reacted with **{count} Star**."; "lng_paid_react_toast_text#other" = "You reacted with **{count} Stars**."; "lng_paid_react_undo" = "Undo"; "lng_paid_react_show_in_top" = "Show me in Top Senders"; "lng_paid_react_anonymous" = "Anonymous"; "lng_paid_comment_title" = "Highlight and Pin"; "lng_paid_comment_about" = "Highlight and pin your message by adding Stars for {name}."; "lng_paid_comment_button" = "Add {stars}"; "lng_paid_comment_pin_about" = "pin in chat"; "lng_paid_comment_limit_about#one" = "character"; "lng_paid_comment_limit_about#other" = "characters"; "lng_paid_comment_emoji_about#one" = "emoji"; "lng_paid_comment_emoji_about#other" = "emoji"; "lng_paid_reaction_title" = "React with Stars"; "lng_paid_reaction_about" = "Highlight and pin your message by sending Stars to {name}."; "lng_paid_reaction_button" = "Send {stars}"; "lng_paid_admin_title" = "Receive Stars from Viewers"; "lng_paid_admin_about" = "Viewers can send you Star Reactions."; "lng_sensitive_tag" = "18+"; "lng_sensitive_title" = "18+"; "lng_sensitive_text" = "This media may contain sensitive content suitable only for adults. Do you still want to view it?"; "lng_sensitive_always" = "Always show 18+ media"; "lng_sensitive_view" = "View Anyway"; "lng_sensitive_toast" = "You can update the visibility of sensitive media in **Settings > Chat Settings > Sensitive content**"; "lng_translate_show_original" = "Show Original"; "lng_translate_return_original" = "View Original ({language})"; "lng_translate_bar_to" = "Translate to {name}"; "lng_translate_bar_to_other" = "Translate to {name}"; "lng_translate_menu_to" = "Translate To"; "lng_translate_menu_dont" = "Don't translate {name}"; "lng_translate_menu_dont_other" = "Don't translate {name}"; "lng_translate_menu_hide" = "Hide"; "lng_translate_hidden_user" = "Translation bar hidden for this chat."; "lng_translate_hidden_group" = "Translation bar is now hidden for this group."; "lng_translate_hidden_channel" = "Translation bar is now hidden for this channel."; "lng_translate_dont_added" = "{name} added to the Do Not Translate list."; "lng_translate_settings" = "Settings"; "lng_translate_undo" = "Undo"; "lng_translate_cocoon_menu" = "Translations are powered by\n**{emoji} Cocoon**. {link}"; "lng_translate_cocoon_link" = "How does it work?"; "lng_translate_cocoon_title" = "Cocoon"; "lng_translate_cocoon_subtitle" = "**Cocoon** ({text}) handles AI tasks **safely** and **efficiently**."; "lng_translate_cocoon_explain" = "**Co**nfidential **Co**mpute **O**pen **N**etwork"; "lng_translate_cocoon_private_title" = "Private"; "lng_translate_cocoon_private_text" = "No third party can access any data, such as translations, inside {mention}."; "lng_translate_cocoon_private_mention" = "@cocoon"; "lng_translate_cocoon_efficient_title" = "Efficient"; "lng_translate_cocoon_efficient_text" = "Cocoon has allowed Telegram to reduce translation costs by 6x."; "lng_translate_cocoon_everyone_title" = "For Everyone"; "lng_translate_cocoon_everyone_text" = "Any developer can use Cocoon for AI features. Learn more at {domain}."; "lng_translate_cocoon_everyone_domain" = "cocoon.org"; "lng_translate_cocoon_text" = "Want to integrate Cocoon into your projects?\nReach out at {link}"; "lng_translate_cocoon_text_link" = "t.me/cocoon?direct"; "lng_translate_cocoon_done" = "Understood"; "lng_downloads_section" = "Downloads"; "lng_downloads_view_in_chat" = "View in chat"; "lng_downloads_view_in_section" = "View in downloads"; "lng_downloads_delete_sure_one" = "Do you want to delete this file?"; "lng_downloads_delete_sure_all" = "Do you want to delete all files?"; "lng_downloads_delete_sure#one" = "Do you want to delete {count} file?"; "lng_downloads_delete_sure#other" = "Do you want to delete {count} files?"; "lng_downloads_delete_in_cloud_one" = "It will be deleted from your disk, but will remain accessible in the cloud."; "lng_downloads_delete_in_cloud" = "They will be deleted from your disk, but will remain accessible in the cloud."; "lng_send_image_empty" = "File: {name} is empty and can't be sent."; "lng_send_images_selected#one" = "{count} image selected"; "lng_send_images_selected#other" = "{count} images selected"; "lng_send_files_selected#one" = "{count} file selected"; "lng_send_files_selected#other" = "{count} files selected"; "lng_send_grouped" = "Group items"; "lng_send_compressed_one" = "Compress the image"; "lng_send_compressed" = "Compress images"; "lng_send_high_quality" = "High Quality"; "lng_send_as_documents_one" = "Send as a document"; "lng_send_as_documents" = "Send as documents"; "lng_send_media_invalid_files" = "Sorry, no valid files found."; "lng_send_image" = "Send an image"; "lng_send_file" = "Send as a file"; "lng_send_video" = "Send a video file"; "lng_forward_choose" = "Forward to…"; "lng_forward_cant" = "Sorry, no way to forward here :("; "lng_forward_share_contact" = "Share contact to {recipient}?"; "lng_forward_share_cant" = "Sorry, no way to share contact here :("; "lng_forward_send_files_cant" = "Sorry, no way to send media here :("; "lng_forward_send" = "Send"; "lng_forward_messages#one" = "{count} forwarded message"; "lng_forward_messages#other" = "{count} forwarded messages"; "lng_forwarding_from#one" = "{user} and {count} other"; "lng_forwarding_from#other" = "{user} and {count} others"; "lng_forwarding_from_two" = "{user} and {second_user}"; "lng_inline_switch_choose" = "Choose conversation..."; "lng_inline_switch_cant" = "Sorry, no way to write here :("; "lng_preview_reply_to" = "Reply to {name}"; "lng_preview_reply_to_quote" = "Reply to quote from {name}"; "lng_preview_reply_to_task" = "Reply to task from {title}"; "lng_preview_reply_to_poll_option" = "Reply to poll option from {title}"; "lng_suggest_bar_title" = "Suggest a Post Below"; "lng_suggest_bar_text" = "Click to offer a price for publishing."; "lng_suggest_bar_priced" = "{amount} for publishing anytime."; "lng_suggest_bar_dated" = "Publish on {date}"; "lng_suggest_options_title" = "Suggest a Message"; "lng_suggest_options_change" = "Suggest Changes"; "lng_suggest_options_stars_offer" = "Offer Stars"; "lng_suggest_options_stars_request" = "Request Stars"; "lng_suggest_options_stars_price" = "Enter Price in Stars"; "lng_suggest_options_stars_price_about" = "Choose how many Stars to pay to publish this message."; "lng_suggest_options_ton_offer" = "Offer TON"; "lng_suggest_options_ton_request" = "Request TON"; "lng_suggest_options_ton_price" = "Enter Price in TON"; "lng_suggest_options_ton_price_about" = "Choose how many TON to pay to publish this message."; "lng_suggest_options_date" = "Time"; "lng_suggest_options_date_any" = "Anytime"; "lng_suggest_options_date_publish" = "Publish"; "lng_suggest_options_date_now" = "Publish Now"; "lng_suggest_options_date_about" = "Select the date and time you want the message to be published. The post will remain available for at least 24 hours from this date."; "lng_suggest_options_you_get_stars#one" = "You will receive {count} Star ({percent}) for publishing this post."; "lng_suggest_options_you_get_stars#other" = "You will receive {count} Stars ({percent}) for publishing this post."; "lng_suggest_options_you_get_ton#one" = "You will receive {count} TON ({percent}) for publishing this post."; "lng_suggest_options_you_get_ton#other" = "You will receive {count} TON ({percent}) for publishing this post."; "lng_suggest_options_stars_warning" = "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust."; "lng_suggest_options_offer" = "Offer {amount}"; "lng_suggest_options_offer_free" = "Offer for Free"; "lng_suggest_options_update" = "Update Terms"; "lng_suggest_options_update_date" = "Update Time"; "lng_suggest_action_decline" = "Decline"; "lng_suggest_action_accept" = "Accept"; "lng_suggest_action_change" = "Suggest Changes"; "lng_suggest_action_your" = "You suggest to post this message."; "lng_suggest_action_his" = "{from} suggests to post this message."; "lng_suggest_action_price_label" = "Price"; "lng_suggest_action_price_free" = "Free"; "lng_suggest_action_time_label" = "Time"; "lng_suggest_action_time_any" = "Anytime"; "lng_suggest_action_agreement" = "Agreement reached!"; "lng_suggest_action_agree_date" = "The post will be automatically published on {channel} {date}."; "lng_suggest_action_your_charged_stars#one" = "You have been charged **{count} Star**."; "lng_suggest_action_your_charged_stars#other" = "You have been charged **{count} Stars**."; "lng_suggest_action_your_charged_ton#one" = "You have been charged **{count} TON**."; "lng_suggest_action_your_charged_ton#other" = "You have been charged **{count} TON**."; "lng_suggest_action_his_charged_stars#one" = "{from} has been charged **{count} Star**."; "lng_suggest_action_his_charged_stars#other" = "{from} has been charged **{count} Stars**."; "lng_suggest_action_his_charged_ton#one" = "{from} has been charged **{count} TON**."; "lng_suggest_action_his_charged_ton#other" = "{from} has been charged **{count} TON**."; "lng_suggest_action_agree_receive_stars" = "{channel} will receive the Stars once the post has been live for 24 hours."; "lng_suggest_action_agree_receive_ton" = "{channel} will receive TON once the post has been live for 24 hours."; "lng_suggest_action_agree_removed_stars" = "If {channel} removes the post before it has been live for 24 hours, the Stars will be refunded."; "lng_suggest_action_agree_removed_ton" = "If {channel} removes the post before it has been live for 24 hours, TON will be refunded."; "lng_suggest_action_your_not_enough_stars" = "**Transaction failed** because you didn't have enough Stars."; "lng_suggest_action_your_not_enough_ton" = "**Transaction failed** because you didn't have enough TON."; "lng_suggest_action_his_not_enough_stars" = "**Transaction failed** because the user didn't have enough Stars."; "lng_suggest_action_his_not_enough_ton" = "**Transaction failed** because the user didn't have enough TON."; "lng_suggest_action_declined" = "{from} rejected the message."; "lng_suggest_action_declined_reason" = "{from} rejected the message with the comment."; "lng_suggest_change_price" = "{from} suggests a new price for the message."; "lng_suggest_change_time" = "{from} suggests a new time for the message."; "lng_suggest_change_price_time" = "{from} suggests a new price and time for the message."; "lng_suggest_change_content" = "{from} suggests changes for the message."; "lng_suggest_change_price_label" = "New Price"; "lng_suggest_change_time_label" = "New Time"; "lng_suggest_change_text_label" = "Check the suggested message below"; "lng_suggest_menu_edit_message" = "Edit Message"; "lng_suggest_menu_edit_price" = "Edit Price"; "lng_suggest_menu_edit_time" = "Edit Time"; "lng_suggest_decline_title" = "Decline"; "lng_suggest_decline_text" = "Do you want to decline publishing this post from {from}?"; "lng_suggest_decline_text_to" = "Do you want to decline publishing this post to {channel}?"; "lng_suggest_decline_reason" = "Add a reason (optional)"; "lng_suggest_accept_title" = "Accept Terms"; "lng_suggest_accept_text" = "Do you want to publish this post from {from}?"; "lng_suggest_accept_text_to" = "Do you want to publish this post to {channel}?"; "lng_suggest_accept_receive_stars#one" = "{channel} will receive **{count} Star** ({percent}) for publishing {date}."; "lng_suggest_accept_receive_stars#other" = "{channel} will receive **{count} Stars** ({percent}) for publishing {date}."; "lng_suggest_accept_receive_ton#one" = "{channel} will receive **{count} TON** ({percent}) for publishing {date}."; "lng_suggest_accept_receive_ton#other" = "{channel} will receive **{count} TON** ({percent}) for publishing {date}."; "lng_suggest_accept_receive_now_stars#one" = "{channel} will receive **{count} Star** ({percent}) for publishing right now."; "lng_suggest_accept_receive_now_stars#other" = "{channel} will receive **{count} Stars** ({percent}) for publishing right now."; "lng_suggest_accept_receive_now_ton#one" = "{channel} will receive **{count} TON** ({percent}) for publishing right now."; "lng_suggest_accept_receive_now_ton#other" = "{channel} will receive **{count} TON** ({percent}) for publishing right now."; "lng_suggest_accept_receive_if" = "It must remain visible for at least **24** hours after publication."; "lng_suggest_accept_pay_stars#one" = "You will pay **{count} Star** for publishing {date}."; "lng_suggest_accept_pay_stars#other" = "You will pay **{count} Stars** for publishing {date}."; "lng_suggest_accept_pay_ton#one" = "You will pay **{count} TON** for publishing {date}."; "lng_suggest_accept_pay_ton#other" = "You will pay **{count} TON** for publishing {date}."; "lng_suggest_accept_pay_now_stars#one" = "You will pay **{count} Star** for publishing right now."; "lng_suggest_accept_pay_now_stars#other" = "You will pay **{count} Stars** for publishing right now."; "lng_suggest_accept_pay_now_ton#one" = "You will pay **{count} TON** for publishing right now."; "lng_suggest_accept_pay_now_ton#other" = "You will pay **{count} TON** for publishing right now."; "lng_suggest_accept_send" = "Publish"; "lng_suggest_stars_amount#one" = "{count} Star"; "lng_suggest_stars_amount#other" = "{count} Stars"; "lng_suggest_ton_amount#one" = "{count} TON"; "lng_suggest_ton_amount#other" = "{count} TON"; "lng_suggest_warn_title_stars" = "Stars will be lost"; "lng_suggest_warn_title_ton" = "TON will be lost"; "lng_suggest_warn_text_stars" = "You won't receive **Stars** for the post if you delete it now. The post must remain visible for at least **24 hours** after it was published."; "lng_suggest_warn_text_ton" = "You won't receive **TON** for the post if you delete it now. The post must remain visible for at least **24 hours** after it was published."; "lng_suggest_warn_delete_anyway" = "Delete Anyway"; "lng_suggest_low_ton_title" = "{amount} TON Needed"; "lng_suggest_low_ton_text" = "You can add funds to your balance via the third-party platform Fragment."; "lng_suggest_low_ton_fragment" = "Add Funds via Fragment"; "lng_suggest_low_ton_fragment_url" = "https://fragment.com/ads/topup"; "lng_reply_in_another_title" = "Reply in..."; "lng_reply_in_another_chat" = "Reply in Another Chat"; "lng_reply_in_author" = "Message author"; "lng_reply_in_chats_list" = "Your chats"; "lng_reply_show_in_chat" = "Show in Chat"; "lng_reply_remove" = "Do Not Reply"; "lng_reply_about_quote" = "You can select a specific part to quote."; "lng_reply_options_header" = "Reply to Message"; "lng_reply_options_quote" = "Update Quote"; "lng_reply_header_short" = "Reply"; "lng_reply_quote_selected" = "Quote Selected"; "lng_reply_from_private_chat" = "This reply is from a private chat."; "lng_reply_quote_long_title" = "Quote too long!"; "lng_reply_quote_long_text" = "The selected text is too long to quote."; "lng_link_options_header" = "Link Preview Settings"; "lng_link_header_short" = "Link"; "lng_link_move_up" = "Move Up"; "lng_link_move_down" = "Move Down"; "lng_link_shrink_photo" = "Shrink Photo"; "lng_link_enlarge_photo" = "Enlarge Photo"; "lng_link_shrink_video" = "Shrink Video"; "lng_link_enlarge_video" = "Enlarge Video"; "lng_link_remove" = "Do Not Preview"; "lng_link_about_choose" = "Click on a link to generate its preview."; "lng_share_cant" = "Sorry, no way to share here :("; "lng_reply_cant" = "You can't reply to messages from before this group was upgraded to a supergroup.\n\nGroups get automatically upgraded when they reach 200 members or when you start using advanced features like chat history permissions or granular admin settings."; "lng_reply_cant_forward" = "Sorry, you can't reply to a message that was sent before the group was upgraded to a supergroup. Do you wish to forward it and add your comment?"; "lng_share_title" = "Share to"; "lng_share_at_time_title" = "Share at {time} to"; "lng_share_copy_link" = "Copy share link"; "lng_share_confirm" = "Send"; "lng_share_wrong_user" = "This game was opened from a different user."; "lng_share_game_link_copied" = "Game link copied to clipboard."; "lng_share_done" = "Done!"; "lng_share_message_to_saved_messages" = "Message forwarded to **Saved Messages**."; "lng_share_messages_to_saved_messages" = "Messages forwarded to **Saved Messages**."; "lng_share_message_to_chat" = "Message forwarded to **{chat}**."; "lng_share_messages_to_chat" = "Messages forwarded to **{chat}**."; "lng_share_message_to_two_chats" = "Message forwarded to **{user}** and **{chat}**."; "lng_share_messages_to_two_chats" = "Messages forwarded to **{user}** and **{chat}**."; "lng_share_message_to_many_chats#one" = "Message forwarded to **{count} chat**."; "lng_share_message_to_many_chats#other" = "Message forwarded to **{count} chats**."; "lng_share_messages_to_many_chats#one" = "Messages forwarded to **{count} chat**."; "lng_share_messages_to_many_chats#other" = "Messages forwarded to **{count} chats**."; "lng_share_as_copy" = "As copy"; "lng_share_as_copy_no_text" = "No text"; "lng_contact_phone" = "Phone Number"; "lng_enter_contact_data" = "New Contact"; "lng_contact_mobile_hidden" = "Mobile hidden"; "lng_contact_phone_after" = "Phone number will be visible once {user} adds you as a contact."; "lng_contact_share_phone" = "Share my phone number"; "lng_contact_phone_will_be_shared" = "You can make your phone visible to {user}."; "lng_contact_add_notes" = "Note"; "lng_contact_add_notes_about" = "Notes are only visible to you."; "lng_contact_notes_limit_reached#one" = "You've reached the contact note limit. Please make the note shorter by {count} character."; "lng_contact_notes_limit_reached#other" = "You've reached the contact note limit. Please make the note shorter by {count} characters."; "lng_suggest_photo_for" = "Suggest Photo for {user}"; "lng_suggest_birthday" = "Suggest Date of Birth"; "lng_suggest_birthday_box_title" = "{user}'s Date of Birth"; "lng_suggest_birthday_box_confirm" = "Suggest"; "lng_set_photo_for_user" = "Set Photo for {user}"; "lng_contact_photo_replace_info" = "You can replace {user}'s photo with another photo that only you will see."; "lng_edit_contact_title" = "Edit contact"; "lng_edit_channel_title" = "Edit channel"; "lng_edit_bot_title" = "Edit bot"; "lng_edit_autotranslate" = "Auto-translate messages"; "lng_edit_sign_messages" = "Sign messages"; "lng_edit_sign_messages_about" = "Add names of admins to the messages they post."; "lng_edit_sign_profiles" = "Show authors' profiles"; "lng_edit_sign_profiles_about" = "Add names and photos of admins to the messages they post, linking to their profiles."; "lng_edit_group" = "Edit group"; "lng_edit_channel_color" = "Appearance"; "lng_edit_channel_level_min" = "Level 1+"; "lng_edit_channel_wallpaper" = "Channel wallpaper"; "lng_edit_channel_wallpaper_about" = "Set a wallpaper that will be visible for everyone reading your channel."; "lng_edit_channel_wallpaper_group" = "Set Group Wallpaper"; "lng_edit_channel_wallpaper_about_group" = "Set a wallpaper that will be visible for everyone viewing your group."; "lng_edit_channel_status" = "Channel emoji status"; "lng_edit_channel_status_about" = "Choose a status that will be shown next to the channel's name."; "lng_edit_channel_status_group" = "Set Group Emoji Status"; "lng_edit_channel_status_about_group" = "Choose a status that will be shown next to the group's name."; "lng_edit_channel_personal_channel" = "Set as Personal Channel"; "lng_edit_self_title" = "Edit your name"; "lng_confirm_contact_data" = "New Contact"; "lng_add_contact" = "Create"; "lng_add_contact_button" = "New contact"; "lng_contacts_header" = "Contacts"; "lng_menu_not_contact" = "This number is not on Telegram"; "lng_contacts_hidden_stories" = "Hidden Stories"; "lng_contacts_stories_status#one" = "{count} story"; "lng_contacts_stories_status#other" = "{count} stories"; "lng_contacts_stories_status_new#one" = "{count} new story"; "lng_contacts_stories_status_new#other" = "{count} new stories"; "lng_contact_not_joined" = "Unfortunately {name} has not joined Telegram yet, but you can send them an invitation.\n\nWe will notify you when any of your contacts join Telegram."; "lng_try_other_contact" = "Try someone else"; "lng_create_group_link" = "Link"; "lng_create_group_invite_link" = "Invite link"; "lng_create_group_description" = "Description (optional)"; "lng_drag_images_here" = "Drop images here"; "lng_drag_photos_here" = "Drop photos here"; "lng_drag_files_here" = "Drop files here"; "lng_drag_media_here" = "Drop photos and videos"; "lng_drag_to_send_quick" = "to send them in a quick way"; "lng_drag_to_send_no_compression" = "to send them without compression"; "lng_drag_to_send_files" = "to send them as documents"; "lng_drag_to_send_media" = "to send them as media files"; "lng_selected_clear" = "Cancel"; "lng_selected_delete" = "Delete"; "lng_selected_forward" = "Forward"; "lng_selected_send_now" = "Send now"; "lng_selected_cancel_sure_this" = "Cancel uploading?"; "lng_selected_upload_stop" = "Stop"; "lng_selected_delete_sure_this" = "Do you want to delete this message?"; "lng_selected_delete_sure#one" = "Do you want to delete {count} message?"; "lng_selected_delete_sure#other" = "Do you want to delete {count} messages?"; "lng_selected_remove_saved_music" = "Do you want to remove this file from your profile?"; "lng_saved_music_added" = "Audio added to your Profile."; "lng_saved_music_removed" = "Audio removed from your Profile."; "lng_delete_photo_sure" = "Do you want to delete this photo?"; "lng_delete_for_everyone_hint#one" = "This will delete it for everyone in this chat."; "lng_delete_for_everyone_hint#other" = "This will delete them for everyone in this chat."; "lng_delete_for_me_chat_hint#one" = "This will delete it just for you, not for other participants of the chat."; "lng_delete_for_me_chat_hint#other" = "This will delete them just for you, not for other participants of the chat."; "lng_delete_for_me_hint#one" = "This will delete it just for you."; "lng_delete_for_me_hint#other" = "This will delete them just for you."; "lng_delete_clear_for_me" = "This will clear history just for you, not for other participants of the chat."; "lng_edit_auto_delete_settings" = "Edit Auto-Delete Settings"; "lng_enable_auto_delete" = "Enable Auto-Delete"; "lng_selected_unsend_about_user_one" = "You can also delete the message you sent from {user}'s inbox by checking \"Unsend my messages\"."; "lng_selected_unsend_about_user#one" = "You can also delete the {count} message you sent from {user}'s inbox by checking \"Unsend my messages\"."; "lng_selected_unsend_about_user#other" = "You can also delete the {count} messages you sent from {user}'s inbox by checking \"Unsend my messages\"."; "lng_selected_unsend_about_group_one" = "You can also delete the message you sent from the inboxes of other group members by checking \"Unsend my messages\"."; "lng_selected_unsend_about_group#one" = "You can also delete the {count} message you sent from the inboxes of other group members by checking \"Unsend my messages\"."; "lng_selected_unsend_about_group#other" = "You can also delete the {count} messages you sent from the inboxes of other group members by checking \"Unsend my messages\"."; "lng_delete_for_everyone_check" = "Delete for everyone"; "lng_delete_for_other_check" = "Also delete for {user}"; "lng_delete_for_other_my" = "Unsend my messages"; "lng_box_delete" = "Delete"; "lng_box_leave" = "Leave"; "lng_upload_sure_stop" = "Are you sure you want to stop uploading your files?\n\nIf you do, you'll need to start over."; "lng_download_sure_stop" = "Are you sure you want to stop downloading your files?\n\nIf you do, you'll need to start over."; "lng_upload_show_file" = "Show file"; "lng_about_version" = "version {version}"; "lng_about_text1" = "Unofficial free messaging app based on {api_link}\nfor speed and security."; "lng_about_text1_api" = "Telegram API"; "lng_about_text2" = "This software is licensed under {gpl_link} version 3.\nSource code is available on {github_link}."; "lng_about_text3" = "Visit the {faq_link} for more info."; "lng_about_text3_faq" = "Telegram FAQ"; "lng_about_done" = "Done"; "lng_search_no_results" = "No messages found"; "lng_search_found_results#one" = "Found {count} message"; "lng_search_found_results#other" = "Found {count} messages"; "lng_search_global_results" = "Global search results"; "lng_search_messages_from" = "Show messages from"; "lng_search_messages_n_of_amount" = "{n} of {amount}"; "lng_search_messages_none" = "No results"; "lng_search_filter_all" = "All chats"; "lng_search_filter_private" = "Private chats"; "lng_search_filter_group" = "Group chats"; "lng_search_filter_channel" = "Channels"; "lng_search_sponsored_button" = "Ad ⋮"; "lng_media_save_progress" = "{ready} of {total} {mb}"; "lng_mediaview_save_as" = "Save As..."; "lng_mediaview_copy" = "Copy"; "lng_mediaview_copy_frame" = "Copy Frame"; "lng_mediaview_forward" = "Forward"; "lng_mediaview_share_at_time" = "Share at {time}"; "lng_mediaview_delete" = "Delete"; "lng_mediaview_save_to_profile" = "Post to Profile"; "lng_mediaview_pin_story_done" = "Story pinned"; "lng_mediaview_pin_story_about" = "Now it will be always shown on the top."; "lng_mediaview_pin_stories_done#one" = "{count} story pinned"; "lng_mediaview_pin_stories_done#other" = "{count} stories pinned"; "lng_mediaview_pin_stories_about#one" = "Now it will be always shown on the top."; "lng_mediaview_pin_stories_about#other" = "Now they will be always shown on the top."; "lng_mediaview_unpin_story_done" = "Story unpinned."; "lng_mediaview_unpin_stories_done#one" = "{count} story unpinned"; "lng_mediaview_unpin_stories_done#other" = "{count} stories unpinned"; "lng_mediaview_pin_limit#one" = "You can't pin more than {count} story."; "lng_mediaview_pin_limit#other" = "You can't pin more than {count} stories."; "lng_mediaview_archive_story" = "Archive Story"; "lng_mediaview_photos_all" = "View all photos"; "lng_mediaview_files_all" = "View all files"; "lng_mediaview_single_photo" = "Single Photo"; "lng_mediaview_group_photo" = "Group Photo"; "lng_mediaview_channel_photo" = "Channel Photo"; "lng_mediaview_profile_photo" = "Profile Photo"; "lng_mediaview_profile_public_photo" = "Public Photo"; "lng_mediaview_profile_photo_by_you" = "Photo set by you"; "lng_mediaview_file_n_of_amount" = "{file} {n} of {amount}"; "lng_mediaview_n_of_amount" = "Photo {n} of {amount}"; "lng_mediaview_doc_image" = "File"; "lng_mediaview_today" = "today at {time}"; "lng_mediaview_yesterday" = "yesterday at {time}"; "lng_mediaview_just_now" = "just now"; "lng_mediaview_minutes_ago#one" = "{count} minute ago"; "lng_mediaview_minutes_ago#other" = "{count} minutes ago"; "lng_mediaview_hours_ago#one" = "{count} hour ago"; "lng_mediaview_hours_ago#other" = "{count} hours ago"; "lng_mediaview_date_time" = "{date} at {time}"; "lng_mediaview_set_userpic" = "Set as Main"; "lng_mediaview_report_profile_photo" = "Report"; "lng_mediaview_title" = "Media viewer"; "lng_mediaview_saved_to" = "Image was saved to your {downloads} folder"; "lng_mediaview_saved_images_to" = "Images were saved to your {downloads} folder"; "lng_mediaview_video_saved_to" = "Video file was saved to your {downloads} folder"; "lng_mediaview_downloads" = "Downloads"; "lng_mediaview_playback_speed" = "Playback speed: {speed}"; "lng_mediaview_rotate_video" = "Rotate video"; "lng_mediaview_quality_auto" = "Auto"; "lng_theme_preview_title" = "Theme Preview"; "lng_theme_preview_generating" = "Generating color theme preview..."; "lng_theme_preview_invalid" = "Invalid data in this theme file."; "lng_theme_preview_apply" = "Apply this theme"; "lng_theme_preview_users#one" = "{count} person is using this theme"; "lng_theme_preview_users#other" = "{count} people are using this theme"; "lng_new_version_wrap" = "Telegram Desktop was updated to version {version}\n\n{changes}\n\nFull version history is available here:\n{link}"; "lng_new_version_minor" = "— Bug fixes and other minor improvements"; "lng_menu_insert_unicode" = "Insert Unicode control character"; "lng_menu_formatting" = "Formatting"; "lng_menu_formatting_bold" = "Bold"; "lng_menu_formatting_italic" = "Italic"; "lng_menu_formatting_underline" = "Underline"; "lng_menu_formatting_strike_out" = "Strikethrough"; "lng_menu_formatting_blockquote" = "Quote"; "lng_menu_formatting_monospace" = "Monospace"; "lng_menu_formatting_spoiler" = "Spoiler"; "lng_menu_formatting_date" = "Date"; "lng_menu_formatting_link_create" = "Create link"; "lng_menu_formatting_link_edit" = "Edit link"; "lng_menu_formatting_clear" = "Clear formatting"; "lng_formatting_date_title" = "Choose date and time"; "lng_formatting_link_create_title" = "Create link"; "lng_formatting_link_edit_title" = "Edit link"; "lng_formatting_link_text" = "Text"; "lng_formatting_link_url" = "URL"; "lng_formatting_link_create" = "Create"; "lng_formatting_code_title" = "Code Language"; "lng_formatting_code_language" = "Language for syntax highlighting."; "lng_formatting_code_auto" = "Auto-Detect"; "lng_text_copied" = "Text copied to clipboard."; "lng_code_copied" = "Code copied to clipboard."; "lng_date_copied" = "Date copied to clipboard."; "lng_date_relative_now" = "now"; "lng_date_relative_seconds_ago#one" = "{count} second ago"; "lng_date_relative_seconds_ago#other" = "{count} seconds ago"; "lng_date_relative_minutes_ago#one" = "{count} minute ago"; "lng_date_relative_minutes_ago#other" = "{count} minutes ago"; "lng_date_relative_hours_ago#one" = "{count} hour ago"; "lng_date_relative_hours_ago#other" = "{count} hours ago"; "lng_date_relative_days_ago#one" = "{count} day ago"; "lng_date_relative_days_ago#other" = "{count} days ago"; "lng_date_relative_months_ago#one" = "{count} month ago"; "lng_date_relative_months_ago#other" = "{count} months ago"; "lng_date_relative_years_ago#one" = "{count} year ago"; "lng_date_relative_years_ago#other" = "{count} years ago"; "lng_date_relative_in_seconds#one" = "in {count} second"; "lng_date_relative_in_seconds#other" = "in {count} seconds"; "lng_date_relative_in_minutes#one" = "in {count} minute"; "lng_date_relative_in_minutes#other" = "in {count} minutes"; "lng_date_relative_in_hours#one" = "in {count} hour"; "lng_date_relative_in_hours#other" = "in {count} hours"; "lng_date_relative_in_days#one" = "in {count} day"; "lng_date_relative_in_days#other" = "in {count} days"; "lng_date_relative_in_months#one" = "in {count} month"; "lng_date_relative_in_months#other" = "in {count} months"; "lng_date_relative_in_years#one" = "in {count} year"; "lng_date_relative_in_years#other" = "in {count} years"; "lng_context_copy_date" = "Copy Date"; "lng_context_add_to_calendar" = "Add to Calendar"; "lng_context_set_reminder" = "Set a Reminder"; "lng_reminder_scheduled_in" = "Reminder scheduled in {link}."; "lng_spellchecker_submenu" = "Spelling"; "lng_spellchecker_add" = "Add to Dictionary"; "lng_spellchecker_remove" = "Remove from Dictionary"; "lng_spellchecker_ignore" = "Ignore word"; "lng_full_name" = "{first_name} {last_name}"; "lng_confirm_phone_link_invalid" = "This link is broken or expired."; "lng_confirm_phone_title" = "Cancel account reset"; "lng_confirm_phone_about" = "Somebody with access to your phone number {phone} has requested to delete your Telegram account and reset your 2-Step Verification password.\n\nIf this wasn't you, please enter the code we've just sent you via SMS to your number. You can also cancel this by changing your phone number to a number you control."; "lng_confirm_phone_success" = "Success!\n\nThe deletion process was canceled for your account {phone}. You may close this window now."; "lng_confirm_phone_send" = "Send"; "lng_confirm_phone_enter_code" = "Please enter the code."; "lng_theme_editor_no_keys" = "No keys in the palette yet"; "lng_theme_editor_cant_change_theme" = "You can't apply a new theme while editing the color palette. Please close the theme editor first."; "lng_theme_editor_new_keys" = "Not in the palette yet"; "lng_theme_editor_background_image" = "Background Image"; "lng_theme_editor_saved_to_jpg" = "Saved to JPEG, {size}"; "lng_theme_editor_read_from_jpg" = "JPEG image, {size}"; "lng_theme_editor_read_from_png" = "PNG image, {size}"; "lng_theme_editor_choose_image" = "Choose Background Image"; "lng_theme_editor_choose_name" = "Save Theme File"; "lng_theme_editor_error" = "The editor encountered an error :( See 'log.txt' for details."; "lng_theme_editor_sure_close" = "Are you sure you want to close the editor? Your changes won't be saved."; "lng_theme_editor_need_auth" = "You need to log in to save your theme."; "lng_theme_editor_need_unlock" = "You need to unlock Telegram to save your theme."; "lng_theme_editor_done" = "Theme exported successfully!"; "lng_theme_editor_title" = "Edit color palette"; "lng_theme_editor_save_button" = "Save theme"; "lng_theme_editor_create_title" = "Create theme"; "lng_theme_editor_create" = "Create"; "lng_theme_editor_name" = "Theme name"; "lng_theme_editor_create_description" = "Your new theme will be based on your currently selected colors and wallpaper. Alternatively, you can import an existing theme or color palette from a file."; "lng_theme_editor_attach_description" = "You can create desktop part of your theme based on your currently selected colors and wallpaper. Alternatively, you can import existing theme or color palette from file."; "lng_theme_editor_import_existing" = "Import existing theme"; "lng_theme_editor_save_title" = "Save theme"; "lng_theme_editor_link_about" = "Your theme will be updated for all users each time you change it. Anyone can install it using this link.\n\nTheme links must be longer than 5 characters and use a-z, 0-9 and underscores."; "lng_theme_editor_menu_export" = "Export theme"; "lng_theme_editor_menu_import" = "Import theme"; "lng_theme_editor_menu_show" = "Show palette file"; "lng_payments_webview_no_use" = "Unfortunately, you can't use payments with current system configuration."; "lng_payments_webview_install_edge" = "Please install {link}."; "lng_payments_webview_install_webkit" = "Please install WebKitGTK (webkit2gtk-4.1/webkit2gtk-4.0) using your package manager."; "lng_payments_webview_update_windows" = "Please update your system to Windows 8.1 or later."; "lng_payments_sure_close" = "Are you sure you want to close this payment form? The changes you made will be lost."; "lng_payments_receipt_label" = "Receipt"; "lng_payments_receipt_label_test" = "Test receipt"; "lng_payments_invoice_label" = "Invoice"; "lng_payments_invoice_label_test" = "Test invoice"; "lng_payments_receipt_button" = "Receipt"; "lng_payments_success" = "You paid {amount} for {title}."; "lng_payments_checkout_title" = "Checkout"; "lng_payments_receipt_title" = "Receipt"; "lng_payments_total_label" = "Total"; "lng_payments_date_label" = "Paid"; "lng_payments_pay_amount" = "Pay {amount}"; "lng_payments_payment_method" = "Payment Method"; "lng_payments_new_card" = "New Card..."; "lng_payments_shipping_address" = "Shipping Address"; "lng_payments_address_street1" = "Address 1"; "lng_payments_address_street2" = "Address 2"; "lng_payments_address_city" = "City"; "lng_payments_address_state" = "State"; "lng_payments_address_country" = "Country"; "lng_payments_address_postcode" = "Postcode"; "lng_payments_shipping_method" = "Shipping Method"; "lng_payments_info_name" = "Name"; "lng_payments_info_email" = "Email"; "lng_payments_info_phone" = "Phone"; "lng_payments_to_provider_phone_email" = "Phone and Email will be passed to {provider} as billing info."; "lng_payments_to_provider_email" = "Email will be passed to {provider} as billing info."; "lng_payments_to_provider_phone" = "Phone will be passed to {provider} as billing info."; "lng_payments_processed_by" = "Processed by {provider}"; "lng_payments_warning_title" = "Warning"; "lng_payments_warning_body" = "Neither Telegram, nor {bot1} will have access to your credit card information. Credit card details will be handled only by the payment system, {provider}.\n\nPayments will go directly to the developer of {bot2}. Telegram cannot provide any guarantees, so proceed at your own risk. In case of problems, please contact the developer of {bot3} or your bank."; "lng_payments_shipping_address_title" = "Shipping Information"; "lng_payments_card_title" = "New Card"; "lng_payments_card_number" = "Card Number"; "lng_payments_card_cvc" = "CVC"; "lng_payments_card_expire_date" = "MM / YY"; "lng_payments_card_holder" = "Cardholder name"; "lng_payments_billing_address" = "Billing Information"; "lng_payments_billing_country" = "Country"; "lng_payments_billing_zip_code" = "Zip Code"; "lng_payments_save_information" = "Save Information for future use"; "lng_payments_need_password" = "You can save your payment information for future use. Please turn on Two-Step Verification to enable this."; "lng_payments_password_title" = "Payment Confirmation"; "lng_payments_password_description" = "You saved the payment method {card}. To use it for payment, please enter your 2-Step-Verification password."; "lng_payments_password_submit" = "Pay"; "lng_payments_tips_label" = "Tip (Optional)"; "lng_payments_tips_box_title" = "Add Tip"; "lng_payments_tips_max" = "Max possible tip amount: {amount}"; "lng_payments_shipping_not_available" = "Shipping to the selected country is not available."; "lng_payments_card_declined" = "Your card was declined."; "lng_payments_payment_failed" = "Payment failed. Your card has not been billed."; "lng_payments_precheckout_failed" = "The bot couldn't process your payment. Your card has not been billed."; "lng_payments_precheckout_timeout" = "The bot didn't respond in time. Your card has not been billed."; "lng_payments_precheckout_stars_failed" = "The bot couldn't process your payment."; "lng_payments_precheckout_stars_timeout" = "The bot didn't respond in time."; "lng_payments_already_paid" = "You have already paid for this item."; "lng_payments_terms_title" = "Terms of Service"; "lng_payments_terms_text" = "Subscribe and accept Terms of Service of {bot}?"; "lng_payments_terms_text_once" = "Do you accept the Terms of Service of {bot}?"; "lng_payments_terms_agree" = "I agree to {link}"; "lng_payments_terms_link" = "Terms of Service"; "lng_payments_terms_accept" = "Accept"; "lng_call_status_incoming" = "is calling you..."; "lng_call_status_connecting" = "connecting..."; "lng_call_status_exchanging" = "exchanging encryption keys..."; "lng_call_status_waiting" = "waiting..."; "lng_call_status_requesting" = "requesting..."; "lng_call_status_hanging" = "hanging up..."; "lng_call_status_ended" = "call ended"; "lng_call_status_failed" = "failed to connect"; "lng_call_status_ringing" = "ringing..."; "lng_call_status_busy" = "line busy"; "lng_call_status_group_invite" = "Telegram Group Call"; "lng_call_status_sure" = "Click on the Camera icon if you want to start a video call."; "lng_call_fingerprint_tooltip" = "If the emoji on {user}'s screen are the same, this call is 100% secure"; "lng_call_error_not_available" = "Sorry, you cannot call {user} because of their privacy settings. You can ask them to modify their setting or to call you instead."; "lng_call_error_outdated" = "{user}'s app does not support calls. They need to update their app before you can call them."; "lng_call_error_no_camera" = "No camera could be found. Please make sure that your camera is connected to the computer."; "lng_call_error_camera_not_started" = "You can switch to video call once you're connected."; "lng_call_error_camera_outdated" = "{user}'s app does not support video calls. They need to update their app before you can call them."; "lng_call_error_audio_io" = "There seems to be a problem with your sound card. Please make sure that your computer's speakers and microphone are working and try again."; "lng_call_error_add_not_started" = "You can add more people once you're connected."; "lng_call_bar_hangup" = "End call"; "lng_call_leave_to_other_sure" = "End your active call and join this video chat?"; "lng_call_leave_to_other_sure_channel" = "Do you want to end your active call and join a live stream in this channel?"; "lng_call_box_title" = "Calls"; "lng_call_box_about" = "You haven't made any Telegram calls yet."; "lng_call_box_status_today" = "{time}"; "lng_call_box_status_yesterday" = "yesterday at {time}"; "lng_call_box_status_date" = "{date} at {time}"; "lng_call_box_status_group" = "({amount}) {status}"; "lng_call_box_clear_all" = "Clear All"; "lng_call_box_clear_sure" = "Are you sure you want to completely clear your calls log?"; "lng_call_box_clear_button" = "Clear"; "lng_call_box_groupcalls_subtitle" = "Active video chats"; "lng_call_outgoing" = "Outgoing call"; "lng_call_video_outgoing" = "Outgoing video call"; "lng_call_group_outgoing" = "Outgoing group call"; "lng_call_incoming" = "Incoming call"; "lng_call_video_incoming" = "Incoming video call"; "lng_call_group_incoming" = "Incoming group call"; "lng_call_missed" = "Missed call"; "lng_call_video_missed" = "Missed video call"; "lng_call_group_missed" = "Missed group call"; "lng_call_cancelled" = "Canceled call"; "lng_call_video_cancelled" = "Canceled video call"; "lng_call_declined" = "Declined call"; "lng_call_video_declined" = "Declined video call"; "lng_call_group_declined" = "Declined group call"; "lng_call_duration_info" = "{time}, {duration}"; "lng_call_type_and_duration" = "{type} ({duration})"; "lng_call_invitation" = "Group call invitation"; "lng_call_ongoing" = "Ongoing group call"; "lng_call_rate_label" = "Please rate the quality of your call"; "lng_call_rate_comment" = "Comment (optional)"; "lng_call_start" = "Start Call"; "lng_call_start_video" = "Start Video"; "lng_call_stop_video" = "Stop Video"; "lng_call_screencast" = "Screencast"; "lng_call_add_people" = "Add People"; "lng_call_end_call" = "End Call"; "lng_call_mute_audio" = "Mute"; "lng_call_unmute_audio" = "Unmute"; "lng_call_accept" = "Accept"; "lng_call_decline" = "Decline"; "lng_call_redial" = "Redial"; "lng_call_cancel" = "Cancel"; "lng_call_microphone_off" = "{user}'s microphone is off"; "lng_call_battery_level_low" = "{user}'s battery level is low"; "lng_group_call_title" = "Video Chat"; "lng_group_call_title_channel" = "Live Stream"; "lng_group_call_active" = "speaking"; "lng_group_call_inactive" = "listening"; "lng_group_call_raised_hand_status" = "wants to speak"; "lng_group_call_settings" = "Settings"; "lng_group_call_video" = "Video"; "lng_group_call_message" = "Message"; "lng_group_call_screen_share_start" = "Share Screen"; "lng_group_call_screen_share_stop" = "Stop Sharing"; "lng_group_call_screen_title" = "Screen {index}"; "lng_group_call_screen_share_audio" = "Share System Audio"; "lng_group_call_sharing_screen_options" = "Sharing Options"; "lng_group_call_choose_source" = "Choose Source"; "lng_group_call_unmute" = "Unmute"; "lng_group_call_unmute_sub" = "Hold space bar to temporarily unmute."; "lng_group_call_you_are_live" = "You are Live"; "lng_group_call_force_muted" = "Muted by admin"; "lng_group_call_force_muted_sub" = "You are in Listen Only mode"; "lng_group_call_raised_hand" = "You asked to speak"; "lng_group_call_connecting" = "Connecting..."; "lng_group_call_leave" = "Leave"; "lng_group_call_leave_title" = "Leave video chat"; "lng_group_call_leave_title_call" = "Leave group call"; "lng_group_call_leave_title_channel" = "Leave live stream"; "lng_group_call_leave_sure" = "Do you want to leave this video chat?"; "lng_group_call_leave_sure_call" = "Do you want to leave this group call?"; "lng_group_call_leave_sure_channel" = "Are you sure you want to leave this live stream?"; "lng_group_call_close" = "Close"; "lng_group_call_close_sure" = "Video chat is scheduled. You can abort it or just close this panel."; "lng_group_call_close_sure_channel" = "Live stream is scheduled. You can abort it or just close this panel."; "lng_group_call_also_cancel" = "Abort video chat"; "lng_group_call_also_cancel_channel" = "Abort live stream"; "lng_group_call_leave_to_other_sure" = "Leave your currently active video chat and join this video chat?"; "lng_group_call_leave_to_other_sure_channel" = "Do you want to leave your active video chat and join a live stream in this channel?"; "lng_group_call_leave_channel_to_other_sure" = "Do you want to leave your active live stream and join a video chat in this group?"; "lng_group_call_leave_channel_to_other_sure_channel" = "Do you want to leave your active live stream and join a live stream in this channel?"; "lng_group_call_create_sure" = "Start a video chat in this group?"; "lng_group_call_create_sure_channel" = "Are you sure you want to start a live stream in this channel as your personal account?"; "lng_group_call_join_sure_personal" = "Are you sure you want to join this video chat as your personal account?"; "lng_group_call_muted_no_camera" = "You can't turn on video while you're muted by admin."; "lng_group_call_muted_no_screen" = "You can't share your screen while you're muted by admin."; "lng_group_call_chat_no_camera" = "You can't turn on video in this chat."; "lng_group_call_chat_no_screen" = "You can't share your screen in this chat."; "lng_group_call_failed_screen" = "An error occurred. Screencast has stopped."; "lng_group_call_failed_camera" = "Couldn't enable camera. Another app may be already using the camera. Try closing other apps first."; "lng_group_call_tooltip_screen" = "Share screen"; "lng_group_call_tooltip_camera" = "Your camera is off. Click here to enable camera."; "lng_group_call_tooltip_microphone" = "You are on mute. Click here to speak."; "lng_group_call_tooltip_camera_off" = "Disable camera"; "lng_group_call_tooltip_force_muted" = "Muted by admin. Click if you want to speak."; "lng_group_call_tooltip_raised_hand" = "You asked to speak. We let the speakers know."; "lng_group_call_also_end" = "End video chat"; "lng_group_call_also_end_channel" = "End live stream"; "lng_group_call_settings_title" = "Settings"; "lng_group_call_invite" = "Invite Members"; "lng_group_call_invite_conf" = "Add People"; "lng_group_call_invited_status" = "invited"; "lng_group_call_calling_status" = "calling..."; "lng_group_call_blockchain_only_status" = "listening"; "lng_group_call_muted_by_me_status" = "muted for you"; "lng_group_call_invite_title" = "Invite members"; "lng_group_call_invite_button" = "Invite"; "lng_group_call_confcall_add" = "Call"; "lng_group_call_add_to_group_one" = "{user} isn't a member of «{group}». Add them to the group?"; "lng_group_call_add_to_group_some" = "Some of those users aren't members of «{group}». Add them to the group?"; "lng_group_call_add_to_group_all" = "Those users aren't members of «{group}». Add them to the group?"; "lng_group_call_invite_members" = "Group members"; "lng_group_call_invite_search_results" = "Search results"; "lng_group_call_invite_limit" = "This is currently the maximum allowed number of participants."; "lng_group_call_new_muted" = "Mute new participants"; "lng_group_call_enable_messages" = "Enable messages"; "lng_group_call_speakers" = "Speakers"; "lng_group_call_microphone" = "Microphone"; "lng_group_call_push_to_talk" = "Push-to-Talk Shortcut"; "lng_group_call_ptt_shortcut" = "Edit Keyboard Shortcut"; "lng_group_call_ptt_recording" = "Stop Recording"; "lng_group_call_ptt_delay_ms" = "{amount} ms"; "lng_group_call_ptt_delay_s" = "{amount} s"; "lng_group_call_ptt_delay" = "Release delay: {delay}"; "lng_group_call_share" = "Share Invite Link"; "lng_group_call_noise_suppression" = "Enable Noise Suppression"; "lng_group_call_video_paused" = "Video is paused"; "lng_group_call_share_speaker" = "Users with this link can speak"; "lng_group_call_copy_speaker_link" = "Copy Speaker Link"; "lng_group_call_copy_listener_link" = "Copy Listener Link"; "lng_group_call_end" = "End Video Chat"; "lng_group_call_end_channel" = "End Live Stream"; "lng_group_call_cancel" = "Abort Video Chat"; "lng_group_call_cancel_channel" = "Abort Live Stream"; "lng_group_call_join" = "Join"; "lng_group_call_join_confirm" = "Join the video chat {chat}?"; "lng_group_call_join_confirm_channel" = "Do you want to join the live stream {chat}?"; "lng_group_call_invite_done_user" = "You invited {user} to the video chat."; "lng_group_call_invite_done_many#one" = "You invited **{count} participant** to the video chat."; "lng_group_call_invite_done_many#other" = "You invited **{count} participants** to the video chat."; "lng_group_call_no_members" = "Click to join"; "lng_group_call_members#one" = "{count} participant"; "lng_group_call_members#other" = "{count} participants"; "lng_group_call_context_mute" = "Mute"; "lng_group_call_context_unmute" = "Allow to speak"; "lng_group_call_context_remove_hand" = "Cancel request to speak"; "lng_group_call_context_mute_for_me" = "Mute for me"; "lng_group_call_context_unmute_for_me" = "Unmute for me"; "lng_group_call_context_pin_camera" = "Pin video"; "lng_group_call_context_unpin_camera" = "Unpin video"; "lng_group_call_context_pin_screen" = "Pin screencast"; "lng_group_call_context_unpin_screen" = "Unpin screencast"; "lng_group_call_context_remove" = "Remove"; "lng_group_call_context_cancel_invite" = "Discard invite"; "lng_group_call_context_stop_ringing" = "Stop calling"; "lng_group_call_context_ban_from_call" = "Ban from call"; "lng_group_call_remove_channel" = "Remove {channel} from the video chat and ban them?"; "lng_group_call_remove_channel_from_channel" = "Remove {channel} from the live stream?"; "lng_group_call_mac_access" = "Telegram Desktop does not have access to system wide keyboard input required for Push to Talk."; "lng_group_call_mac_input" = "Please allow **Input Monitoring** for Telegram in Privacy Settings."; "lng_group_call_mac_accessibility" = "Please allow **Accessibility** for Telegram in Privacy Settings.\n\nYou may need to restart the app."; "lng_group_call_mac_screencast_access" = "Telegram Desktop does not have access to screen recording required for Screen Sharing."; "lng_group_call_mac_recording" = "Please allow **Screen Recording** for Telegram in Privacy Settings."; "lng_group_call_mac_settings" = "Open Settings"; "lng_group_call_start_as_header" = "Start Video Chat as..."; "lng_group_call_start_as_header_channel" = "Start Live Stream as..."; "lng_group_call_join_as_header" = "Join Video Chat as..."; "lng_group_call_join_as_header_channel" = "Join Live Stream as..."; "lng_group_call_display_as_header" = "Display me as..."; "lng_group_call_join_as_about" = "Choose whether you want to be displayed as your personal account or as your channel."; "lng_group_call_or_schedule" = "You can also {link}."; "lng_group_call_schedule" = "schedule a video chat"; "lng_group_call_schedule_channel" = "schedule a live stream"; "lng_group_call_schedule_title" = "Schedule Video Chat"; "lng_group_call_schedule_title_channel" = "Schedule Live Stream"; "lng_group_call_schedule_notified_group" = "Members of the group will be notified that the video chat will start in {duration}."; "lng_group_call_schedule_notified_channel" = "Subscribers of the channel will be notified that the live stream starts in {duration}."; "lng_group_call_scheduled_status" = "Scheduled"; "lng_group_call_scheduled_title" = "Scheduled Video Chat"; "lng_group_call_scheduled_title_channel" = "Scheduled Live Stream"; "lng_group_call_starts_short" = "Starts {when}"; "lng_group_call_starts" = "Video Chat starts {when}"; "lng_group_call_starts_channel" = "Live Stream starts {when}"; "lng_group_call_starts_today" = "today at {time}"; "lng_group_call_starts_tomorrow" = "tomorrow at {time}"; "lng_group_call_starts_date" = "{date} at {time}"; "lng_group_call_starts_in" = "Starts in"; "lng_group_call_late_by" = "Late by"; "lng_group_call_starts_short_today" = "Today, {time}"; "lng_group_call_starts_short_tomorrow" = "Tomorrow, {time}"; "lng_group_call_starts_short_date" = "{date}, {time}"; "lng_group_call_start_now" = "Start Now"; "lng_group_call_start_now_sure" = "Are you sure you want to start the video chat now?"; "lng_group_call_start_now_sure_channel" = "Are you sure you want to start the live stream now?"; "lng_group_call_set_reminder" = "Set Reminder"; "lng_group_call_cancel_reminder" = "Cancel Reminder"; "lng_group_call_join_as_personal" = "personal account"; "lng_group_call_edit_title" = "Edit Video Chat Title"; "lng_group_call_edit_title_channel" = "Edit live stream title"; "lng_group_call_recording_start" = "Start Recording"; "lng_group_call_recording_stop" = "Stop Recording"; "lng_group_call_recording_started" = "Audio recording started."; "lng_group_call_recording_started_video" = "Started recording the video stream."; "lng_group_call_recording_started_channel" = "Live stream recording started."; "lng_group_call_recording_stopped" = "Recording stopped."; "lng_group_call_recording_stopped_channel" = "Live stream recording stopped."; "lng_group_call_recording_saved" = "Recording of the audio stream saved to Saved Messages."; "lng_group_call_recording_saved_video" = "Video saved to Saved Messages."; "lng_group_call_pinned_camera_me" = "Your video is pinned."; "lng_group_call_pinned_screen_me" = "Your screencast is pinned."; "lng_group_call_pinned_camera" = "{user}'s video is pinned."; "lng_group_call_pinned_screen" = "{user}'s screencast is pinned."; "lng_group_call_unpinned_camera_me" = "Your video is unpinned."; "lng_group_call_unpinned_screen_me" = "Your screencast is unpinned."; "lng_group_call_unpinned_camera" = "{user}'s video is unpinned."; "lng_group_call_unpinned_screen" = "{user}'s screencast is unpinned."; "lng_group_call_sure_screencast" = "{user} is sharing their screen. This action will pin your screencast for all participants."; "lng_group_call_pinned_on_top" = "Live stream is pinned on top."; "lng_group_call_unpinned_on_top" = "Live stream is unpinned from top."; "lng_group_call_recording_start_sure" = "Record this chat and save the result into an audio file?\n\nParticipants will see that the chat is being recorded."; "lng_group_call_recording_stop_sure" = "Do you want to stop recording this video chat?"; "lng_group_call_recording_start_field" = "Recording Title"; "lng_group_call_recording_start_button" = "Start"; "lng_group_call_recording_start_title" = "Add Title"; "lng_group_call_recording_start_checkbox" = "Also record video"; "lng_group_call_recording_start_audio_subtitle" = "This chat will be recorded into an audio file"; "lng_group_call_recording_start_video_subtitle" = "Choose video orientation"; "lng_group_call_is_recorded" = "The audio stream is being recorded."; "lng_group_call_is_recorded_video" = "The video stream is being recorded."; "lng_group_call_is_recorded_channel" = "Live stream is being recorded."; "lng_group_call_can_speak_here" = "You can now speak."; "lng_group_call_can_speak" = "You can now speak in {chat}."; "lng_group_call_title_changed" = "Video chat title changed to {title}"; "lng_group_call_title_changed_channel" = "Live stream title changed to {title}"; "lng_group_call_join_as_changed" = "Participants of this video chat will now see you as {name}"; "lng_group_call_join_as_changed_channel" = "Participants of this live stream will now see you as {name}"; "lng_group_call_no_stream_admin" = "Oops! Telegram doesn't see any stream coming from your streaming app. Please make sure you entered the right Server URL and Stream Key in your app."; "lng_group_call_no_stream" = "{group} is currently not broadcasting live stream data to Telegram."; "lng_menu_start_group_call" = "Start video chat"; "lng_menu_start_group_call_scheduled" = "Schedule video chat"; "lng_menu_start_group_call_with" = "Stream with..."; "lng_menu_start_group_call_join" = "Join video chat"; "lng_menu_start_group_call_options" = "Video chat"; "lng_menu_start_group_call_channel" = "Start live stream"; "lng_menu_start_group_call_scheduled_channel" = "Schedule live stream"; "lng_menu_start_group_call_with_channel" = "Stream with..."; "lng_group_call_rtmp_title" = "Stream with other apps"; "lng_group_call_rtmp_url_subtitle" = "Server URL"; "lng_group_call_rtmp_url_copy" = "Copy Server URL"; "lng_group_call_rtmp_url_copied" = "Server URL copied to clipboard."; "lng_group_call_rtmp_key_subtitle" = "Stream Key"; "lng_group_call_rtmp_key_copy" = "Copy Stream Key"; "lng_group_call_rtmp_key_copied" = "Stream Key copied to clipboard."; "lng_group_call_rtmp_key_warning" = "**Never share your Stream Key with anyone or show it on stream!**"; "lng_group_call_rtmp_info" = "To stream video with another app, enter these Server URL and Stream Key in your streaming app. Software encoding recommended (x264 in OBS).\n\nOnce you start broadcasting in your streaming app, click Start Streaming below."; "lng_group_call_rtmp_start" = "Start Streaming"; "lng_group_call_rtmp_revoke" = "Revoke Stream Key"; "lng_group_call_rtmp_revoke_sure" = "Are you sure you want to revoke your Stream Key?"; "lng_group_call_rtmp_viewers#one" = "{count} viewer"; "lng_group_call_rtmp_viewers#other" = "{count} viewers"; "lng_confcall_join_title" = "Group Call"; "lng_confcall_join_text" = "You are invited to join a Telegram Call."; "lng_confcall_join_text_inviter" = "{user} is inviting you to join a Telegram Call."; "lng_confcall_already_joined_one" = "{user} already joined this call."; "lng_confcall_already_joined_two" = "{user} and {other} already joined this call."; "lng_confcall_already_joined_three" = "{user}, {other} and {third} already joined this call."; "lng_confcall_already_joined_many#one" = "{user}, {other} and **{count}** other person already joined this call."; "lng_confcall_already_joined_many#other" = "{user}, {other} and **{count}** other people already joined this call."; "lng_confcall_join_button" = "Join Group Call"; "lng_confcall_create_call" = "Start New Call"; "lng_confcall_create_call_description#one" = "You can add up to {count} participant to a call."; "lng_confcall_create_call_description#other" = "You can add up to {count} participants to a call."; "lng_confcall_create_title" = "New Call"; "lng_confcall_create_link" = "Create Call Link"; "lng_confcall_create_link_description" = "You can create a link that will allow your friends on Telegram to join the call."; "lng_confcall_link_revoke" = "Revoke link"; "lng_confcall_link_revoked_title" = "Link Revoked"; "lng_confcall_link_inactive" = "This link is no longer active."; "lng_confcall_link_revoked_text" = "A new link has been generated."; "lng_confcall_link_title" = "Call Link"; "lng_confcall_link_about" = "Anyone on Telegram can join your call by following the link below."; "lng_confcall_link_or" = "or"; "lng_confcall_link_join" = "Be the first to join the call and add people from there. {link}"; "lng_confcall_link_join_link" = "Open call {arrow}"; "lng_confcall_inactive_title" = "Start Group Call"; "lng_confcall_inactive_about" = "This call is no longer active.\nYou can start a new one."; "lng_confcall_invite_done_user" = "You're calling {user} to join."; "lng_confcall_invite_done_many#one" = "You're calling **{count} person** to join."; "lng_confcall_invite_done_many#other" = "You're calling **{count} people** to join."; "lng_confcall_invite_already_user" = "{user} is already in the call."; "lng_confcall_invite_already_many#one" = "**{count} person** is already in the call."; "lng_confcall_invite_already_many#other" = "**{count} people** are already in the call."; "lng_confcall_invite_privacy_user" = "You cannot call {user} because of their privacy settings."; "lng_confcall_invite_privacy_many#one" = "You cannot call **{count} person** because of their privacy settings."; "lng_confcall_invite_privacy_many#other" = "You cannot call **{count} people** because of their privacy settings."; "lng_confcall_invite_fail_user" = "Couldn't call {user} to join."; "lng_confcall_invite_fail_many#one" = "Couldn't call **{count} person** to join."; "lng_confcall_invite_fail_many#other" = "Couldn't call **{count} people** to join."; "lng_confcall_invite_kicked_user" = "{user} was banned from the call."; "lng_confcall_invite_kicked_many#one" = "**{count} person** was removed from the call."; "lng_confcall_invite_kicked_many#other" = "**{count} people** were removed from the call."; "lng_confcall_not_accessible" = "This call is no longer accessible."; "lng_confcall_participants_limit" = "This call reached the participants limit."; "lng_confcall_sure_remove" = "Remove {user} from the call?"; "lng_confcall_e2e_badge" = "End-to-End Encrypted"; "lng_confcall_e2e_badge_small" = "E2E Encrypted"; "lng_confcall_e2e_about" = "These four emoji represent the call's encryption key. They must match for all participants and change when someone joins or leaves."; "lng_no_mic_permission" = "Telegram needs microphone access so that you can make calls and record voice messages."; "lng_player_message_today" = "today at {time}"; "lng_player_message_yesterday" = "yesterday at {time}"; "lng_player_message_date" = "{date} at {time}"; "lng_audio_player_reverse" = "Reverse order"; "lng_audio_player_shuffle" = "Shuffle"; "lng_audio_transcribe_long" = "This voice message is too long."; "lng_audio_transcribe_trials_left#one" = "You have {count} free transcription left until {date}."; "lng_audio_transcribe_trials_left#other" = "You have {count} free transcriptions left until {date}."; "lng_audio_transcribe_trials_over" = "You have used all your free transcriptions this week. Wait until {date} to use it again or subscribe to {link} now."; "lng_rights_edit_admin" = "Admin rights"; "lng_rights_edit_admin_header" = "What can this admin do?"; "lng_rights_edit_admin_rank_name" = "Custom title"; "lng_rights_edit_admin_rank_about" = "A title that members will see instead of '{title}'."; "lng_context_add_my_tag" = "Add tag"; "lng_context_edit_my_tag" = "Edit tag"; "lng_context_add_member_tag" = "Add member tag"; "lng_context_edit_member_tag" = "Edit member tag"; "lng_rights_edit_tag_title" = "Edit tag"; "lng_rights_tag_about" = "Add short tag next to {name}'s name."; "lng_rights_tag_about_self" = "Share your role, title, or how you're known in this group. Your tag is visible to all members."; "lng_tag_info_title_user" = "Member Tags"; "lng_tag_info_title_admin" = "Admin Tags"; "lng_tag_info_title_owner" = "Owner Tags"; "lng_tag_info_text_user" = "This grey tag {emoji} is {author}'s member tag in {group}."; "lng_tag_info_text_admin" = "This green tag {emoji} is {author}'s admin tag in {group}."; "lng_tag_info_text_owner" = "This purple tag {emoji} is {author}'s owner tag in {group}."; "lng_tag_info_preview_member" = "Member Tag"; "lng_tag_info_preview_admin" = "Admin Tag"; "lng_tag_info_preview_owner" = "Owner Tag"; "lng_tag_info_add_my_tag" = "Add My Tag"; "lng_tag_info_edit_my_tag" = "Edit My Tag"; "lng_tag_info_admins_only" = "Only admins can change tags in this group."; "lng_rights_promote_member" = "Promote to Admin"; "lng_rights_remove_member" = "Remove from Group"; "lng_rights_dismiss_admin" = "Dismiss Admin"; "lng_rights_about_add_admins_yes" = "This admin will be able to add new admins with equal or fewer rights."; "lng_rights_about_add_admins_no" = "This admin will not be able to add new admins."; "lng_rights_about_by" = "This admin promoted by {user} on {date}."; "lng_rights_about_admin_cant_edit" = "You can't edit the rights of this admin."; "lng_rights_about_restriction_cant_edit" = "You cannot change the restrictions for this user."; "lng_rights_restriction_for_all" = "This option is disabled for all members in Group Permissions."; "lng_rights_permission_for_all" = "This option is enabled for all members in Group Permissions."; "lng_rights_permission_unavailable" = "This permission is not available in public groups."; "lng_rights_permission_in_discuss" = "This permission is not available in discussion groups."; "lng_rights_permission_cant_edit" = "You cannot change this permission."; "lng_rights_user_restrictions" = "User permissions"; "lng_rights_user_restrictions_header" = "What can this member do?"; "lng_rights_default_restrictions_header" = "What can members of this group do?"; "lng_rights_slowmode_header" = "Slow mode"; "lng_rights_slowmode_off" = "Off"; "lng_rights_slowmode_about" = "Members will be able to send only one message per this interval."; "lng_rights_slowmode_about_interval" = "Members will be able to send only one message {interval}."; "lng_rights_slowmode_interval_seconds#one" = "every {count} second"; "lng_rights_slowmode_interval_seconds#other" = "every {count} seconds"; "lng_rights_slowmode_interval_minutes#one" = "every {count} minute"; "lng_rights_slowmode_interval_minutes#other" = "every {count} minutes"; "lng_rights_boosts_no_restrict" = "Do not restrict boosters"; "lng_rights_boosts_about" = "Turn this on to always allow users who boosted your group to send messages and media."; "lng_rights_boosts_about_on" = "Choose how many boosts a user must give to the group to bypass restrictions on sending messages."; "lng_rights_charge_stars" = "Charge Stars for Messages"; "lng_rights_charge_stars_about" = "If you turn this on, regular members of the group will have to pay Stars to send messages."; "lng_rights_charge_price" = "Set price per message"; "lng_rights_charge_price_about" = "Your group will receive {percent} of the selected fee ({amount}) for each incoming message."; "lng_slowmode_enabled" = "Slow Mode is active.\nYou can send your next message in {left}."; "lng_slowmode_no_many" = "Slow mode is enabled. You can't send more than one message at a time."; "lng_slowmode_too_long" = "This text is too long to send as one message.\n\nSlow mode is active. You can't send more than one message at once."; "lng_slowmode_seconds#one" = "{count} second"; "lng_slowmode_seconds#other" = "{count} seconds"; "lng_payment_confirm_title" = "Confirm payment"; "lng_payment_confirm_text#one" = "{name} charges **{count}** Star per message."; "lng_payment_confirm_text#other" = "{name} charges **{count}** Stars per message."; "lng_payment_confirm_amount#one" = "**{count}** Star"; "lng_payment_confirm_amount#other" = "**{count}** Stars"; "lng_payment_confirm_users#one" = "You selected **{count}** user who charge Stars for messages."; "lng_payment_confirm_users#other" = "You selected **{count}** users who charge Stars for messages."; "lng_payment_confirm_chats#one" = "You selected **{count}** chat where you pay Stars for messages."; "lng_payment_confirm_chats#other" = "You selected **{count}** chats where you pay Stars for messages."; "lng_payment_confirm_sure#one" = "Would you like to pay {amount} to send **{count}** message?"; "lng_payment_confirm_sure#other" = "Would you like to pay {amount} to send **{count}** messages?"; "lng_payment_confirm_dont_ask" = "Don't ask me again"; "lng_payment_confirm_button#one" = "Pay for {count} Message"; "lng_payment_confirm_button#other" = "Pay for {count} Messages"; "lng_payment_bar_text" = "{name} must pay {cost} for each message to you."; "lng_payment_bar_button" = "Remove Fee"; "lng_payment_refund_title" = "Remove Fee"; "lng_payment_refund_text" = "Are you sure you want to allow {name} to message you for free?"; "lng_payment_refund_channel" = "Do you want to allow {name} to message the channel for free?"; "lng_payment_refund_also#one" = "Refund already paid {count} Star"; "lng_payment_refund_also#other" = "Refund already paid {count} Stars"; "lng_payment_refund_confirm" = "Confirm"; "lng_rights_gigagroup_title" = "Broadcast group"; "lng_rights_gigagroup_convert" = "Convert to Broadcast Group"; "lng_rights_gigagroup_about" = "Broadcast groups can have over 200,000 members, but only admins can send messages in them."; "lng_gigagroup_convert_title" = "Broadcast Groups"; "lng_gigagroup_convert_feature1" = "No limit on the number of members."; "lng_gigagroup_convert_feature2" = "Only admins can send messages."; "lng_gigagroup_convert_feature3" = "Can't be turned back into a regular group."; "lng_gigagroup_convert_sure" = "Convert"; "lng_gigagroup_warning_title" = "Are you sure?"; "lng_gigagroup_warning" = "Regular members of the group (non-admins) will **permanently** lose their right to send messages in the group.\n\nThis action **can't** be undone."; "lng_gigagroup_done" = "Your group can now have more than 200,000 members."; "lng_gigagroup_suggest_title" = "Limit reached"; "lng_gigagroup_suggest_text" = "Your group has reached a limit of **200,000** members.\n\nYou can increase this limit by converting the group to a **broadcast group** where only admins can post. Interested?"; "lng_gigagroup_suggest_more" = "Learn more"; "lng_rights_channel_info" = "Change channel info"; "lng_rights_channel_manage" = "Manage messages"; "lng_rights_channel_post" = "Post messages"; "lng_rights_channel_edit" = "Edit messages of others"; "lng_rights_channel_delete" = "Delete messages of others"; "lng_rights_channel_manage_stories" = "Manage stories"; "lng_rights_channel_post_stories" = "Post stories"; "lng_rights_channel_edit_stories" = "Edit stories of others"; "lng_rights_channel_delete_stories" = "Delete stories of others"; "lng_rights_channel_manage_calls" = "Manage live streams"; "lng_rights_channel_manage_direct" = "Manage direct messages"; "lng_rights_group_info" = "Change group info"; "lng_rights_group_ban" = "Ban users"; "lng_rights_group_invite_link" = "Invite users via link"; "lng_rights_group_invite" = "Add members"; "lng_rights_group_pin" = "Pin messages"; "lng_rights_group_topics" = "Manage topics"; "lng_rights_group_add_topics" = "Create topics"; "lng_rights_group_edit_rank" = "Edit own tags"; "lng_rights_group_edit_rank_single" = "Edit own tag"; "lng_rights_group_manage_calls" = "Manage video chats"; "lng_rights_group_delete" = "Delete messages"; "lng_rights_group_anonymous" = "Remain anonymous"; "lng_rights_group_manage_ranks" = "Edit member tags"; "lng_rights_add_admins" = "Add new admins"; "lng_rights_chat_send_text" = "Send messages"; "lng_rights_chat_send_media" = "Send media"; "lng_rights_chat_send_stickers" = "Send stickers & GIFs"; "lng_rights_chat_send_links" = "Embed links"; "lng_rights_chat_send_polls" = "Send polls"; "lng_rights_chat_add_members" = "Add members"; "lng_rights_chat_photos" = "Photos"; "lng_rights_chat_videos" = "Video files"; "lng_rights_chat_stickers" = "Stickers & GIFs"; "lng_rights_chat_music" = "Music"; "lng_rights_chat_files" = "Files"; "lng_rights_chat_voice_messages" = "Voice messages"; "lng_rights_chat_video_messages" = "Video messages"; "lng_rights_chat_restricted_by" = "Restricted by {user} on {date}."; "lng_rights_chat_banned_by" = "Banned by {user} on {date}."; "lng_rights_chat_banned_until_header" = "Restricted until"; "lng_rights_chat_banned_forever" = "Forever"; "lng_rights_chat_banned_day#one" = "For {count} day"; "lng_rights_chat_banned_day#other" = "For {count} days"; "lng_rights_chat_banned_week#one" = "For {count} week"; "lng_rights_chat_banned_week#other" = "For {count} weeks"; "lng_rights_chat_banned_custom" = "Custom"; "lng_rights_chat_banned_custom_date" = "Until {date}"; "lng_rights_transfer_group" = "Transfer group ownership"; "lng_rights_transfer_channel" = "Transfer channel ownership"; "lng_rights_transfer_check" = "Security check"; "lng_rights_transfer_check_about" = "You can transfer this group to {user} only if you have:"; "lng_rights_transfer_check_about_channel" = "You can transfer this channel to {user} only if you have:"; "lng_rights_transfer_check_password" = "• Enabled **Two-Step Verification** more than **7 days** ago."; "lng_rights_transfer_check_session" = "• Logged in on this device more than **24 hours** ago."; "lng_rights_transfer_check_later" = "Please come back later."; "lng_rights_transfer_set_password" = "Set password"; "lng_rights_transfer_about" = "This will transfer the full **owner rights** for {group} to {user}. The new owner will be free to remove any of your admin privileges or even ban you."; "lng_rights_transfer_sure" = "Change owner"; "lng_rights_transfer_password_title" = "Two-step verification"; "lng_rights_transfer_password_description" = "Please enter your password to complete the transfer."; "lng_rights_transfer_done_group" = "{user} is now the owner of the group."; "lng_rights_transfer_done_channel" = "{user} is now the owner of the channel."; "lng_bots_password_confirm_check_about" = "You can complete this action only if you have:"; "lng_bots_password_confirm_title" = "Two-step verification"; "lng_bots_password_confirm_description" = "Please enter your password to confirm this action."; "lng_restricted_send_message" = "The admins of this group have restricted your ability to send messages."; "lng_restricted_send_photos" = "The admins of this group restricted you from sending photos here."; "lng_restricted_send_videos" = "The admins of this group restricted you from sending videos here."; "lng_restricted_send_music" = "The admins of this group restricted you from sending music here."; "lng_restricted_send_files" = "The admins of this group restricted you from sending files here."; "lng_restricted_send_voice_messages_group" = "The admins of this group restricted you from sending voice messages here."; "lng_restricted_send_video_messages_group" = "The admins of this group restricted you from sending video messages here."; "lng_restricted_send_stickers" = "The admins of this group have restricted your ability to send stickers."; "lng_restricted_send_gifs" = "The admins of this group have restricted your ability to send GIFs."; "lng_restricted_send_inline" = "The admins of this group have restricted your ability to send inline content."; "lng_restricted_send_polls" = "The admins of this group have restricted your ability to send polls."; "lng_restricted_boost_group" = "Boost this group to send messages"; "lng_restricted_send_message_until" = "The admins of this group have restricted you from sending messages until {date}, {time}."; "lng_restricted_send_photos_until" = "The admins of this group restricted you from sending photos here until {date}, {time}."; "lng_restricted_send_videos_until" = "The admins of this group restricted you from sending videos here until {date}, {time}."; "lng_restricted_send_music_until" = "The admins of this group restricted you from sending music here until {date}, {time}."; "lng_restricted_send_files_until" = "The admins of this group restricted you from sending files here until {date}, {time}."; "lng_restricted_send_voice_messages_until" = "The admins of this group restricted you from sending voice messages here until {date}, {time}."; "lng_restricted_send_video_messages_until" = "The admins of this group restricted you from sending video messages here until {date}, {time}."; "lng_restricted_send_stickers_until" = "The admins of this group have restricted your ability to send stickers until {date}, {time}."; "lng_restricted_send_gifs_until" = "The admins of this group have restricted your ability to send GIFs until {date}, {time}."; "lng_restricted_send_inline_until" = "The admins of this group have restricted your ability to send inline content until {date}, {time}."; "lng_restricted_send_polls_until" = "The admins of this group have restricted your ability to send polls until {date}, {time}."; "lng_restricted_send_message_all" = "Sending messages is not allowed in this group."; "lng_restricted_send_photos_all" = "Sending photos isn't allowed in this group."; "lng_restricted_send_videos_all" = "Sending videos isn't allowed in this group."; "lng_restricted_send_music_all" = "Sending music isn't allowed in this group."; "lng_restricted_send_files_all" = "Sending files isn't allowed in this group."; "lng_restricted_send_voice_messages_all" = "Sending voice messages isn't allowed in this group."; "lng_restricted_send_video_messages_all" = "Sending video messages isn't allowed in this group."; "lng_restricted_send_stickers_all" = "Stickers aren’t allowed in this group."; "lng_restricted_send_gifs_all" = "Sending GIFs isn't allowed in this group."; "lng_restricted_send_inline_all" = "Sending inline content isn't allowed in this group."; "lng_restricted_send_polls_all" = "Sorry, sending polls is not allowed in this group."; "lng_restricted_send_public_polls" = "Sorry, polls with visible votes can't be forwarded to channels."; "lng_restricted_send_todo_lists" = "Sorry, Checklists can't be forwarded to channels."; "lng_restricted_send_paid_media" = "Sorry, paid media can't be sent to this channel."; "lng_restricted_send_voice_messages" = "{user} doesn't accept voice messages."; "lng_restricted_send_video_messages" = "{user} doesn't accept video messages."; "lng_restricted_send_non_premium" = "Only Premium users can message {user}."; "lng_restricted_send_non_premium_more" = "Learn more..."; "lng_send_non_premium_text" = "Subscribe to **Premium**\nto message {user}."; "lng_send_non_premium_go" = "Go Premium"; "lng_send_non_premium_story" = "Replies restricted"; "lng_send_non_premium_unlock" = "unlock"; "lng_send_non_premium_message_toast" = "**{user}** only accepts messages from contacts and {link} subscribers."; "lng_send_non_premium_message_toast_link" = "Telegram Premium"; "lng_send_charges_stars_channel" = "{channel} charges {amount} per message to its admin."; "lng_send_free_channel" = "Send a direct message to the administrator of {channel}."; "lng_send_charges_stars_text" = "{user} charges {amount} for each message."; "lng_send_charges_stars_go" = "Buy Stars"; "lng_exceptions_list_title" = "Exceptions"; "lng_removed_list_title" = "Removed users"; "lng_admin_log_title_all" = "All actions"; "lng_admin_log_title_selected" = "Selected actions"; "lng_admin_log_filter_title" = "Filter"; "lng_admin_log_filter_all_actions" = "All actions"; "lng_admin_log_filter_actions_type_subtitle" = "Filter actions by type"; "lng_admin_log_filter_actions_member_section" = "Members And Admins"; "lng_admin_log_filter_actions_subscriber_section" = "Subscribers And Admins"; "lng_admin_log_filter_restrictions" = "New restrictions"; "lng_admin_log_filter_admins_new" = "Admin rights"; "lng_admin_log_filter_members_new" = "New members"; "lng_admin_log_filter_subscribers_new" = "New subscribers"; "lng_admin_log_filter_actions_settings_section" = "Group Settings"; "lng_admin_log_filter_actions_channel_settings_section" = "Channel Settings"; "lng_admin_log_filter_info_group" = "Group info"; "lng_admin_log_filter_info_channel" = "Channel info"; "lng_admin_log_filter_actions_messages_section" = "Messages"; "lng_admin_log_filter_messages_deleted" = "Deleted messages"; "lng_admin_log_filter_messages_edited" = "Edited messages"; "lng_admin_log_filter_messages_pinned" = "Pinned messages"; "lng_admin_log_filter_voice_chats" = "Video chats"; "lng_admin_log_filter_voice_chats_channel" = "Live stream"; "lng_admin_log_filter_invite_links" = "Invite links"; "lng_admin_log_filter_members_removed" = "Members leaving"; "lng_admin_log_filter_subscribers_removed" = "Subscribers leaving"; "lng_admin_log_filter_topics" = "Topics"; "lng_admin_log_filter_sub_extend" = "Subscription Renewals"; "lng_admin_log_filter_edit_rank" = "Tag Changes"; "lng_admin_log_filter_all_admins" = "All users and admins"; "lng_admin_log_filter_actions_admins_subtitle" = "Filter actions by admins"; "lng_admin_log_filter_actions_admins_section" = "Show Actions by All Admins"; "lng_admin_log_about_text" = "This is a list of all notable actions by group members and admins in the last 48 hours."; "lng_admin_log_about_text_channel" = "This is a list of all service actions taken by the channel's admins in the last 48 hours."; "lng_admin_log_no_results_title" = "No actions found"; "lng_admin_log_no_results_text" = "No recent actions that match your query were found."; "lng_admin_log_no_results_search_text" = "No recent actions that contain '{query}' have been found."; "lng_admin_log_no_events_title" = "No actions yet"; "lng_admin_log_no_events_text" = "No notable actions taken by the members and admins of this group in the last 48 hours."; "lng_admin_log_no_events_text_channel" = "No notable actions taken\nby the admins of this channel\nin the last 48 hours."; "lng_admin_log_empty_text" = "Empty"; "lng_admin_log_changed_title_channel" = "{from} changed channel name to «{title}»"; "lng_admin_log_changed_description_group" = "{from} edited group description:"; "lng_admin_log_removed_description_group" = "{from} removed group description"; "lng_admin_log_changed_description_channel" = "{from} edited channel description:"; "lng_admin_log_removed_description_channel" = "{from} removed channel description"; "lng_admin_log_previous_description" = "Previous description"; "lng_admin_log_changed_link_group" = "{from} changed group link:"; "lng_admin_log_removed_link_group" = "{from} removed group link"; "lng_admin_log_changed_link_channel" = "{from} changed channel link:"; "lng_admin_log_removed_link_channel" = "{from} removed channel link"; "lng_admin_log_previous_link" = "Previous link"; "lng_admin_log_reordered_link_group" = "{from} reordered group links:"; "lng_admin_log_reordered_link_channel" = "{from} reordered channel links:"; "lng_admin_log_previous_links_order" = "Previous order"; "lng_admin_log_activated_link" = "{from} activated @{link} username"; "lng_admin_log_deactivated_link" = "{from} deactivated @{link} username"; "lng_admin_log_changed_photo_group" = "{from} changed group photo"; "lng_admin_log_changed_photo_channel" = "{from} changed channel photo"; "lng_admin_log_removed_photo_group" = "{from} removed group photo"; "lng_admin_log_removed_photo_channel" = "{from} removed channel photo"; "lng_admin_log_invites_enabled" = "{from} enabled group invites"; "lng_admin_log_invites_disabled" = "{from} disabled group invites"; "lng_admin_log_signatures_enabled" = "{from} enabled signatures"; "lng_admin_log_signatures_disabled" = "{from} disabled signatures"; "lng_admin_log_signature_profiles_enabled" = "{from} enabled showing authors' profiles"; "lng_admin_log_signature_profiles_disabled" = "{from} disabled showing authors' profiles"; "lng_admin_log_forwards_enabled" = "{from} allowed saving content"; "lng_admin_log_forwards_disabled" = "{from} restricted saving content"; "lng_admin_log_history_made_hidden" = "{from} made the group history hidden for new members"; "lng_admin_log_history_made_visible" = "{from} made group history visible for new members"; "lng_admin_log_pinned_message" = "{from} pinned message:"; "lng_admin_log_unpinned_message" = "{from} unpinned message"; "lng_admin_log_edited_caption" = "{from} edited caption:"; "lng_admin_log_edited_media" = "{from} edited media:"; "lng_admin_log_edited_media_and_caption" = "{from} edited media and caption:"; "lng_admin_log_edited_media_and_removed_caption" = "{from} edited media and removed caption:"; "lng_admin_log_removed_caption" = "{from} removed caption"; "lng_admin_log_previous_caption" = "Original caption"; "lng_admin_log_edited_message" = "{from} edited message:"; "lng_admin_log_previous_message" = "Original message"; "lng_admin_log_deleted_message" = "{from} deleted message:"; "lng_admin_log_sent_message" = "{from} sent this message:"; "lng_admin_log_participant_joined" = "{from} joined the group"; "lng_admin_log_participant_joined_channel" = "{from} joined the channel"; "lng_admin_log_participant_joined_by_link" = "{from} joined the group via {link}"; "lng_admin_log_participant_joined_by_link_channel" = "{from} joined the channel via {link}"; "lng_admin_log_participant_joined_by_filter_link" = "{from} joined via folder invite link {link}"; "lng_admin_log_participant_joined_by_filter_link_channel" = "{from} joined via folder invite link {link}"; "lng_admin_log_participant_approved_by_link" = "{from} was approved to join the group via {link} by {user}"; "lng_admin_log_participant_approved_by_link_channel" = "{from} was approved to join the channel via {link} by {user}"; "lng_admin_log_participant_approved_by_request" = "{from} joined the group via public request, approved by {user}"; "lng_admin_log_participant_approved_by_request_channel" = "{from} joined the channel via public request, approved by {user}"; "lng_admin_log_revoke_invite_link" = "{from} revoked invite link {link}"; "lng_admin_log_delete_invite_link" = "{from} deleted the invite link {link}"; "lng_admin_log_participant_left" = "{from} left the group"; "lng_admin_log_participant_left_channel" = "{from} left the channel"; "lng_admin_log_stopped_poll" = "{from} stopped poll:"; "lng_admin_log_invited" = "invited {user}"; "lng_admin_log_banned" = "banned {user}"; "lng_admin_log_banned_until" = "banned {user} {until}"; "lng_admin_log_unbanned" = "unbanned {user}"; "lng_admin_log_restricted" = "changed restrictions for {user} {until}"; "lng_admin_log_promoted" = "changed privileges for {user}"; "lng_admin_log_transferred" = "transferred ownership to {user}"; "lng_admin_log_changed_default_permissions" = "changed default permissions"; "lng_admin_log_changed_stickers_group" = "{from} changed the group {sticker_set}"; "lng_admin_log_changed_stickers_set" = "sticker set"; "lng_admin_log_removed_stickers_group" = "{from} removed the group sticker set"; "lng_admin_log_changed_emoji_group" = "{from} changed the group's {sticker_set}"; "lng_admin_log_changed_emoji_set" = "emoji set"; "lng_admin_log_removed_emoji_group" = "{from} removed the group's emoji set"; "lng_admin_log_changed_linked_chat" = "{from} changed the discussion group to «{chat}»"; "lng_admin_log_removed_linked_chat" = "{from} removed the discussion group"; "lng_admin_log_changed_linked_channel" = "{from} changed the linked channel to «{chat}»"; "lng_admin_log_removed_linked_channel" = "{from} removed the linked channel"; "lng_admin_log_changed_location_chat" = "{from} changed the group location to {address}"; "lng_admin_log_removed_location_chat" = "{from} removed the group location"; "lng_admin_log_changed_slow_mode" = "{from} changed slow mode to {duration}"; "lng_admin_log_removed_slow_mode" = "{from} disabled slow mode"; "lng_admin_log_started_group_call" = "{from} started a new video chat"; "lng_admin_log_started_group_call_channel" = "{from} started a new live stream"; "lng_admin_log_discarded_group_call" = "{from} ended the video chat"; "lng_admin_log_discarded_group_call_channel" = "{from} ended the live stream"; "lng_admin_log_muted_participant" = "{from} muted {user} in a video chat"; "lng_admin_log_muted_participant_channel" = "{from} muted {user} in a live stream"; "lng_admin_log_unmuted_participant" = "{from} unmuted {user} in a video chat"; "lng_admin_log_unmuted_participant_channel" = "{from} unmuted {user} in a live stream"; "lng_admin_log_allowed_unmute_self" = "{from} allowed new video chat participants to speak"; "lng_admin_log_allowed_unmute_self_channel" = "{from} allowed new live stream participants to speak"; "lng_admin_log_disallowed_unmute_self" = "{from} muted new video chat participants"; "lng_admin_log_disallowed_unmute_self_channel" = "{from} muted new live stream participants"; "lng_admin_log_participant_volume" = "{from} changed video chat volume for {user} to {percent}"; "lng_admin_log_participant_volume_channel" = "{from} changed live stream volume for {user} to {percent}"; "lng_admin_log_antispam_enabled" = "{from} enabled aggressive anti-spam"; "lng_admin_log_antispam_disabled" = "{from} disabled aggressive anti-spam"; "lng_admin_log_autotranslate_enabled" = "{from} enabled automatic translation"; "lng_admin_log_autotranslate_disabled" = "{from} disabled automatic translation"; "lng_admin_log_change_color" = "{from} changed channel color from {previous} to {color}"; "lng_admin_log_set_background_emoji" = "{from} set channel background emoji to {emoji}"; "lng_admin_log_change_background_emoji" = "{from} changed channel background emoji from {previous} to {emoji}"; "lng_admin_log_removed_background_emoji" = "{from} removed channel background emoji {emoji}"; "lng_admin_log_change_profile_color" = "{from} changed channel profile color from {previous} to {color}"; "lng_admin_log_set_profile_background_emoji" = "{from} set channel profile background emoji to {emoji}"; "lng_admin_log_change_profile_background_emoji" = "{from} changed channel profile background emoji from {previous} to {emoji}"; "lng_admin_log_removed_profile_background_emoji" = "{from} removed channel profile background emoji {emoji}"; "lng_admin_log_change_profile_color_group" = "{from} changed group profile color from {previous} to {color}"; "lng_admin_log_set_profile_background_emoji_group" = "{from} set group profile background emoji to {emoji}"; "lng_admin_log_change_profile_background_emoji_group" = "{from} changed group profile background emoji from {previous} to {emoji}"; "lng_admin_log_removed_profile_background_emoji_group" = "{from} removed group profile background emoji {emoji}"; "lng_admin_log_change_wallpaper" = "{from} changed channel wallpaper"; "lng_admin_log_set_status" = "{from} set channel emoji status to {emoji}"; "lng_admin_log_change_status" = "{from} changed channel emoji status from {previous} to {emoji}"; "lng_admin_log_removed_status" = "{from} removed channel emoji status {emoji}"; "lng_admin_log_set_status_until" = "{from} set channel emoji status to {emoji} until {date}"; "lng_admin_log_change_status_until" = "{from} changed channel emoji status from {previous} to {emoji} until {date}"; "lng_admin_log_user_with_username" = "{name} ({mention})"; "lng_admin_log_messages_ttl_set" = "{from} enabled messages auto-delete after {duration}"; "lng_admin_log_messages_ttl_changed" = "{from} changed messages auto-delete period from {previous} to {duration}"; "lng_admin_log_messages_ttl_removed" = "{from} disabled messages auto-deletion after {duration}"; "lng_admin_log_reactions_disabled" = "{from} disabled reactions"; "lng_admin_log_reactions_updated" = "{from} updated the list of allowed reactions to: {emoji}"; "lng_admin_log_reactions_allowed_all" = "{from} allowed all reactions"; "lng_admin_log_reactions_allowed_official" = "{from} allowed all official reactions"; "lng_admin_log_edited_invite_link" = "edited invite link {link}"; "lng_admin_log_invite_link_expire_date" = "Expiry date: {previous} → {limit}"; "lng_admin_log_invite_link_usage_limit" = "Usage limit: {previous} → {limit}"; "lng_admin_log_invite_link_label" = "Name: {previous} → {limit}"; "lng_admin_log_invite_link_request_needed" = "Admin approval is now required to join."; "lng_admin_log_invite_link_request_not_needed" = "Admin approval no longer required to join."; "lng_admin_log_topics_enabled" = "{from} enabled topics"; "lng_admin_log_topics_disabled" = "{from} disabled topics"; "lng_admin_log_topics_created" = "{from} created topic {topic}"; "lng_admin_log_topics_changed" = "{from} renamed topic {topic} to {new_topic}"; "lng_admin_log_topics_closed" = "{from} closed topic {topic}"; "lng_admin_log_topics_reopened" = "{from} reopened topic {topic}"; "lng_admin_log_topics_hidden" = "{from} hid topic {topic}"; "lng_admin_log_topics_unhidden" = "{from} unhid topic {topic}"; "lng_admin_log_topics_deleted" = "{from} deleted topic {topic}"; "lng_admin_log_topics_pinned" = "{from} pinned topic {topic}"; "lng_admin_log_topics_unpinned" = "{from} unpinned topic {topic}"; "lng_admin_log_restricted_forever" = "indefinitely"; "lng_admin_log_restricted_until" = "until {date}"; "lng_admin_log_banned_view_messages" = "Read messages"; "lng_admin_log_banned_send_messages" = "Send messages"; "lng_admin_log_banned_send_photos" = "Send photos"; "lng_admin_log_banned_send_videos" = "Send video files"; "lng_admin_log_banned_send_music" = "Send music"; "lng_admin_log_banned_send_files" = "Send files"; "lng_admin_log_banned_send_voice_messages" = "Send voice messages"; "lng_admin_log_banned_send_video_messages" = "Send video messages"; "lng_admin_log_banned_send_stickers" = "Send stickers & GIFs"; "lng_admin_log_banned_embed_links" = "Embed links"; "lng_admin_log_banned_send_polls" = "Send polls"; "lng_admin_log_admin_change_info" = "Change info"; "lng_admin_log_admin_post_messages" = "Post messages"; "lng_admin_log_admin_edit_messages" = "Edit messages"; "lng_admin_log_admin_delete_messages" = "Delete messages"; "lng_admin_log_admin_post_stories" = "Post stories"; "lng_admin_log_admin_edit_stories" = "Edit stories of others"; "lng_admin_log_admin_delete_stories" = "Delete stories"; "lng_admin_log_admin_remain_anonymous" = "Remain anonymous"; "lng_admin_log_admin_ban_users" = "Ban users"; "lng_admin_log_admin_invite_users" = "Add users"; "lng_admin_log_admin_invite_link" = "Invite users via link"; "lng_admin_log_admin_pin_messages" = "Pin messages"; "lng_admin_log_banned_edit_rank" = "Edit own tags"; "lng_admin_log_banned_edit_rank_single" = "Edit own tag"; "lng_admin_log_admin_manage_topics" = "Manage topics"; "lng_admin_log_admin_create_topics" = "Create topics"; "lng_admin_log_admin_manage_calls" = "Manage video chats"; "lng_admin_log_admin_manage_calls_channel" = "Manage live streams"; "lng_admin_log_admin_manage_direct" = "Manage direct messages"; "lng_admin_log_admin_manage_ranks" = "Edit member tags"; "lng_admin_log_admin_add_admins" = "Add new admins"; "lng_admin_log_subscription_extend" = "{name} renewed subscription until {date}"; "lng_admin_log_changed_rank_from" = "{from} changed tag for {user} from \"{previous}\" to \"{tag}\""; "lng_admin_log_set_rank" = "{from} set tag for {user} to \"{tag}\""; "lng_admin_log_removed_rank" = "{from} removed tag for {user} (was \"{previous}\")"; "lng_admin_log_changed_own_rank_from" = "{from} changed own tag from \"{previous}\" to \"{tag}\""; "lng_admin_log_set_own_rank" = "{from} set own tag to \"{tag}\""; "lng_admin_log_removed_own_rank" = "{from} removed own tag (was \"{previous}\")"; "lng_admin_log_antispam_menu_report" = "Report False Positive"; "lng_admin_log_antispam_menu_report_toast" = "You can manage anti-spam settings in {link}."; "lng_admin_log_antispam_menu_report_toast_link" = "Group Info > Administrators"; "lng_terms_signup" = "By signing up,\nyou agree to the {link}."; "lng_terms_signup_link" = "Terms of Service"; "lng_terms_header" = "Terms of Service"; "lng_terms_age#one" = "I confirm that I am {count} or over"; "lng_terms_age#other" = "I confirm that I am {count} or over"; "lng_terms_agree" = "Agree & Continue"; "lng_terms_decline" = "Decline"; "lng_terms_signup_sorry" = "Unfortunately, this means you can't sign up for Telegram.\n\nUnlike other apps, Telegram does not use user data for ad targeting or other commercial purposes. Telegram only stores the information it needs to function as a feature-rich cloud service. You can adjust how your data is used (e.g., delete synced contacts) in Privacy & Security settings.\n\nIf you are not comfortable with Telegram's modest needs, it won't be possible for us to provide you with this service."; "lng_terms_update_sorry" = "We're very sorry, but this means we must part ways here. Unlike others, we don't use your data for ad targeting or other commercial purposes. Telegram only stores the information it needs to function as a secure and feature-rich cloud service. You can adjust how we use your data in Privacy & Security settings.\n\nBut if you're generally not OK with Telegram's modest requirements, it won't be possible for us to provide you with this service. You can delete your account now — or look around some more and delete it later if you feel you're not happy with the way we use your data."; "lng_terms_decline_and_delete" = "Decline & Delete"; "lng_terms_back" = "Back"; "lng_terms_delete_warning" = "Warning, this will irreversibly delete your Telegram account and all the data you store in the Telegram cloud.\n\nImportant: You can Cancel now and export your data first instead of losing it. (To do this, open the latest version of Telegram Desktop and go to Settings > Advanced > Export Telegram data.)"; "lng_terms_delete_now" = "Delete now"; "lng_terms_agree_to_proceed" = "Agree and proceed to {bot}."; "lng_date_input_day" = "Day"; "lng_date_input_month" = "Month"; "lng_date_input_year" = "Year"; "lng_forward_title" = "Forward Message"; "lng_forward_many_title#one" = "Forward {count} Message"; "lng_forward_many_title#other" = "Forward {count} Messages"; "lng_forward_about" = "You can remove the sender's name so that this message will look like it was sent by you."; "lng_forward_many_about" = "You can remove the senders’ names so that these messages will look like they were sent by you."; "lng_forward_show_sender" = "Show sender name"; "lng_forward_show_senders" = "Show sender names"; "lng_forward_show_caption" = "Show caption"; "lng_forward_show_captions" = "Show captions"; "lng_forward_change_recipient" = "Change recipient"; "lng_forward_sender_names_removed" = "Sender names removed"; "lng_forward_header_short" = "Forward"; "lng_forward_action_show_sender" = "Show Sender Name"; "lng_forward_action_show_senders" = "Show Sender Names"; "lng_forward_action_hide_sender" = "Hide Sender Name"; "lng_forward_action_hide_senders" = "Hide Sender Names"; "lng_forward_action_show_caption" = "Show Caption"; "lng_forward_action_show_captions" = "Show Captions"; "lng_forward_action_hide_caption" = "Hide Caption"; "lng_forward_action_hide_captions" = "Hide Captions"; "lng_forward_action_change_recipient" = "Change Recipient"; "lng_forward_action_remove" = "Do Not Forward"; "lng_passport_title" = "Telegram Passport"; "lng_passport_request1" = "{bot} requests access to your personal data"; "lng_passport_request2" = "to sign you up for their services"; "lng_passport_create_password" = "Please create a password which will be used\nto encrypt your personal data."; "lng_passport_about_password" = "This password will also be required whenever\nyou log in to a new device."; "lng_passport_password_create" = "Create a password"; "lng_passport_email_validate" = "Validate"; "lng_passport_code_sent" = "A confirmation code was sent to\n{email}"; "lng_passport_stop_password_sure" = "Are you sure you want to cancel setting up your password?"; "lng_passport_password_placeholder" = "Your password"; "lng_passport_next" = "Next"; "lng_passport_password_wrong" = "The password you entered is not valid."; "lng_passport_header" = "Requested information"; "lng_passport_identity_title" = "Identity document"; "lng_passport_identity_description" = "Upload proof of your identity"; "lng_passport_identity_passport" = "Passport"; "lng_passport_identity_passport_upload" = "Upload a scan of your passport"; "lng_passport_identity_card" = "Identity card"; "lng_passport_identity_card_upload" = "Upload a scan of your identity card"; "lng_passport_identity_license" = "Driver's licence"; "lng_passport_identity_license_upload" = "Upload a scan of your driver's license"; "lng_passport_identity_internal" = "Internal passport"; "lng_passport_identity_internal_upload" = "Upload a scan of your internal passport"; "lng_passport_identity_about" = "The document must contain your photograph, first and last name, date of birth, document number, country of issue, and expiry date."; "lng_passport_address_title" = "Residential address"; "lng_passport_address_description" = "Upload proof of your address"; "lng_passport_address_bill" = "Utility bill"; "lng_passport_address_bill_upload" = "Upload a scan of your utility bill"; "lng_passport_address_statement" = "Bank statement"; "lng_passport_address_statement_upload" = "Upload a scan of your bank statement"; "lng_passport_address_agreement" = "Tenancy agreement"; "lng_passport_address_agreement_upload" = "Upload a scan of your tenancy agreement"; "lng_passport_address_registration" = "Passport registration"; "lng_passport_address_registration_upload" = "Upload a scan of your passport registration page"; "lng_passport_address_temporary" = "Temporary registration"; "lng_passport_address_temporary_upload" = "Upload a scan of your temporary registration"; "lng_passport_address_about" = "To confirm your address, please upload a scan or photo of the selected document (all pages)."; "lng_passport_or_title" = "{document} or {second_document}"; "lng_passport_document_type" = "Please choose the type of your document:"; "lng_passport_upload_document" = "Upload document"; "lng_passport_phone_title" = "Phone number"; "lng_passport_phone_description" = "Enter your phone number"; "lng_passport_email_title" = "Email"; "lng_passport_email_description" = "Enter your email address"; "lng_passport_identity_selfie" = "Take a selfie with your document"; "lng_passport_translation_needed" = "Add an English translation of your document"; "lng_passport_accept_allow" = "You accept the {policy} and allow their {bot} to send you messages."; "lng_passport_allow" = "You allow {bot} to send you messages."; "lng_passport_policy" = "{bot} privacy policy"; "lng_passport_authorize" = "Authorize"; "lng_passport_form_error" = "Could not get authorization form."; "lng_passport_save_value" = "Save"; "lng_passport_scan_index" = "Scan {index}"; "lng_passport_upload_scans" = "Upload scans"; "lng_passport_upload_more" = "Upload additional scans"; "lng_passport_selfie_title" = "Selfie"; "lng_passport_selfie_description" = "Upload a photo of yourself holding your document. Make sure the ID and your face are clearly visible."; "lng_passport_upload_selfie" = "Upload selfie"; "lng_passport_reupload_selfie" = "Reupload selfie"; "lng_passport_front_side_title" = "Front side"; "lng_passport_front_side_description" = "Upload a photo of the front side of the document."; "lng_passport_upload_front_side" = "Upload a scan of the front side"; "lng_passport_reupload_front_side" = "Reupload a scan of the front side"; "lng_passport_reverse_side_title" = "Reverse side"; "lng_passport_reverse_side_description" = "Upload a photo of the reverse side of the document."; "lng_passport_upload_reverse_side" = "Upload a scan of the reverse side"; "lng_passport_reupload_reverse_side" = "Reupload a scan of the reverse side"; "lng_passport_main_page_title" = "Main page"; "lng_passport_main_page_description" = "Upload a scan of the main page of your document."; "lng_passport_upload_main_page" = "Upload a scan of the main page"; "lng_passport_reupload_main_page" = "Reupload a scan of the main page"; "lng_passport_personal_details" = "Personal details"; "lng_passport_personal_details_enter" = "Fill in your personal details"; "lng_passport_document_details" = "Document details"; "lng_passport_choose_image" = "Choose scan image"; "lng_passport_delete_scan_undo" = "Undo"; "lng_passport_scan_uploaded" = "Uploaded on {date}"; "lng_passport_first_name" = "First name"; "lng_passport_middle_name" = "Middle name"; "lng_passport_last_name" = "Last name"; "lng_passport_birth_date" = "Date of birth"; "lng_passport_gender" = "Gender"; "lng_passport_gender_male" = "Male"; "lng_passport_gender_female" = "Female"; "lng_passport_country" = "Citizenship"; "lng_passport_residence_country" = "Residence"; "lng_passport_country_choose" = "Choose country"; "lng_passport_document_number" = "Document Number"; "lng_passport_expiry_date" = "Expiry date"; "lng_passport_native_name_title" = "Name in country of residence"; "lng_passport_native_name_about" = "Your name in the language of your country of residence ({country})."; "lng_passport_native_name_language" = "Your name in {language}"; "lng_passport_native_name_language_about" = "Your name in the language of your country of residence."; "lng_passport_address" = "Address"; "lng_passport_address_enter" = "Provide your address"; "lng_passport_street" = "Street"; "lng_passport_city" = "City"; "lng_passport_state" = "State"; "lng_passport_postcode" = "Postcode"; "lng_passport_translation" = "Translation"; "lng_passport_use_existing" = "USE {existing}"; "lng_passport_use_existing_phone" = "Use the same phone number as on Telegram."; "lng_passport_new_phone" = "Or enter a new phone number"; "lng_passport_new_phone_code" = "Note: You will receive a confirmation code on the phone number you provide."; "lng_passport_use_existing_email" = "Use the same email address as on Telegram."; "lng_passport_new_email" = "Or enter a new email"; "lng_passport_new_email_code" = "Note: You will receive a confirmation code to the email address you provide."; "lng_passport_confirm_phone" = "We've sent an SMS with a confirmation code to your phone {phone}."; "lng_passport_confirm_email" = "We've sent a confirmation code to your email {email}."; "lng_passport_sure_cancel" = "If you continue, your changes will be lost."; "lng_passport_scans_limit_reached" = "Sorry, that's too many scans for one document."; "lng_passport_delete_document" = "Delete document"; "lng_passport_delete_document_sure" = "Are you sure you want to delete this document?"; "lng_passport_delete_details" = "Delete personal details"; "lng_passport_delete_details_sure" = "Are you sure you want to delete your personal details?"; "lng_passport_delete_address" = "Delete address information"; "lng_passport_delete_address_sure" = "Are you sure you want to delete your address information?"; "lng_passport_delete_email" = "Delete email"; "lng_passport_delete_email_sure" = "Are you sure you want to delete your email address?"; "lng_passport_delete_phone" = "Delete phone number"; "lng_passport_delete_phone_sure" = "Are you sure you want to delete your phone number?"; "lng_passport_success" = "Authorization successful!"; "lng_passport_stop_sure" = "Are you sure you want to stop this authorization?"; "lng_passport_stop" = "Stop"; "lng_passport_restart_sure" = "An unexpected error has occurred. Perhaps some changes were made from a different Telegram application. Would you like to restart this authorization?"; "lng_passport_restart" = "Restart"; "lng_passport_error_too_large" = "Sorry, this file is too large."; "lng_passport_error_bad_size" = "Sorry, this image has wrong dimensions."; "lng_passport_error_cant_read" = "Can't read this file. Please choose an image."; "lng_passport_bad_name" = "Please use latin characters only."; "lng_passport_wait_upload" = "Please wait until the file has finished uploading."; "lng_passport_app_out_of_date" = "Sorry, your Telegram app is out of date and can't handle this request. Please update Telegram."; "lng_export_title" = "Export Your Data"; "lng_export_progress_title" = "Exporting your data"; "lng_export_option_info" = "Account information"; "lng_export_option_info_about" = "Your chosen display name, username, phone number and profile photos."; "lng_export_option_contacts" = "Contacts list"; "lng_export_option_contacts_about" = "If you allow access, contacts are continuously synced with Telegram. You can adjust this in Settings > Privacy & Security on mobile devices."; "lng_export_option_stories" = "Story archive"; "lng_export_option_stories_about" = "All stories you posted from Telegram mobile apps."; "lng_export_option_profile_music" = "Music on Profiles"; "lng_export_option_profile_music_about" = "All tracks you saved to your playlist."; "lng_export_option_sessions" = "Active sessions"; "lng_export_option_sessions_about" = "We may store this to display your connected devices in Settings > Privacy & Security > Show all sessions."; "lng_export_header_other" = "Other"; "lng_export_option_other" = "Miscellaneous data"; "lng_export_option_other_about" = "Other types of data not mentioned above (beta)."; "lng_export_header_chats" = "Chat export settings"; "lng_export_header_topic" = "Topic export settings"; "lng_export_option_personal_chats" = "Personal chats"; "lng_export_option_bot_chats" = "Bot chats"; "lng_export_option_private_groups" = "Private groups"; "lng_export_option_private_channels" = "Private channels"; "lng_export_option_public_groups" = "Public groups"; "lng_export_option_public_channels" = "Public channels"; "lng_export_option_only_my" = "Only my messages"; "lng_export_header_media" = "Media export settings"; "lng_export_option_photos" = "Photos"; "lng_export_option_video_files" = "Videos"; "lng_export_option_voice_messages" = "Voice messages"; "lng_export_option_video_messages" = "Video messages"; "lng_export_option_stickers" = "Stickers"; "lng_export_option_gifs" = "GIFs"; "lng_export_option_files" = "Files"; "lng_export_option_size_limit" = "Size limit: {size}"; "lng_export_header_format" = "Location and format"; "lng_export_option_location" = "Download path: {path}"; "lng_export_option_format_location" = "Format: {format}, Path: {path}"; "lng_export_option_choose_format" = "Choose export format"; "lng_export_option_html" = "Human-readable HTML"; "lng_export_option_json" = "Machine-readable JSON"; "lng_export_option_html_and_json" = "Both"; "lng_export_limits" = "From: {from}, to: {till}"; "lng_export_beginning" = "the oldest message"; "lng_export_end" = "present"; "lng_export_from_beginning" = "Reset"; "lng_export_till_end" = "Reset"; "lng_export_start" = "Export"; "lng_export_state_initializing" = "Initializing..."; "lng_export_state_userpics" = "Profile photos"; "lng_export_state_chats_list" = "Processing chats..."; "lng_export_state_chats" = "Chats"; "lng_export_skip_file" = "Skip this file"; "lng_export_progress" = "You can close this window now. Please don't quit Telegram until the data export is completed."; "lng_export_stop" = "Stop"; "lng_export_sure_stop" = "Are you sure you want to stop exporting your data?\n\nIf you do, you'll need to start over."; "lng_export_about_done" = "Your data was successfully exported."; "lng_export_done" = "Show my data"; "lng_export_finished" = "Data export completed."; "lng_export_total_amount" = "Total files: {amount}"; "lng_export_total_size" = "Total size: {size}"; "lng_export_folder" = "Choose export folder"; "lng_export_invalid" = "Sorry, you started a new data export, so this data export has been canceled."; "lng_export_delay" = "For security reasons, you will be able to begin downloading your data in {hours}. We have notified all your devices about the export request to make sure it's authorized and give you time to react if it's not.\n\nPlease come back on {date} and repeat the request using the same device."; "lng_export_delay_less_than_hour" = "less than an hour"; "lng_export_suggest_title" = "Data export ready"; "lng_export_suggest_text" = "You can now download the data you requested. Start exporting data?"; "lng_export_suggest_cancel" = "Not now"; "lng_export_about_telegram" = "Here is the data you requested. Remember: Telegram is ad free, it doesn't use your data for ad targeting and doesn't sell it to others. Telegram only keeps the information it needs to function as a secure and feature-rich cloud service.\n\nCheck out Settings > Privacy & Security on Telegram's mobile apps for the relevant settings."; "lng_export_about_contacts" = "If you allow access, your contacts are continuously synced with Telegram. Thanks to this, you can easily switch to Telegram and immediately connect with friends across all your devices. We use data about your contacts to let you know when they join Telegram, and to display them by the name you set for them in your phone.\n\nYou can disable contact syncing or delete your stored contacts in Settings > Privacy & Security on Telegram's mobile apps."; "lng_export_about_frequent" = "This rating shows which people you are likelier to message frequently. Telegram uses this data to populate the 'People' box at the top of the Search section. This rating is also calculated for inline bots so that the app can suggest the bots you are most likely to use in the attachment menu (or when you start a new message with \"@\").\n\nTo delete this data, go to Settings > Privacy & Security and disable 'Suggest Frequent Contacts' (requires Telegram for iOS v.4.8.3 or Telegram for Android v.4.8.10 or higher)."; "lng_export_about_sessions" = "We store session info to display your connected devices in Settings > Privacy & Security > Active Sessions."; "lng_export_about_web_sessions" = "We store this to display the websites where you logged in using authentication via Telegram. This information is shown in Settings > Privacy & Security > Active Sessions."; "lng_export_about_chats" = "This page lists all chats from this export."; "lng_export_about_left_chats" = "Below are the supergroups and channels from this export that you've left or where you were banned.\n\nNote that when you leave a channel or supergroup you've created, you have the option to either delete it, or simply leave (in case you want to rejoin later, or keep the community alive despite not being a member)."; "lng_language_switch_title" = "Change language?"; "lng_language_switch_about_official" = "You are about to apply a language pack ({lang_name}) that is {percent}% complete.\n\nThis will translate the entire interface. You can suggest corrections in the {link}.\n\nYou can change your language back at any time in Settings."; "lng_language_switch_about_unofficial" = "You are about to apply a custom language pack with the name \"{lang_name}\" that is {percent}% complete.\n\nThis will translate the entire interface. You can suggest corrections on the {link}.\n\nYou can change your language back at any time in Settings."; "lng_language_switch_link" = "translation platform"; "lng_language_switch_apply" = "Apply Language"; "lng_language_not_found" = "Sorry, this language pack doesn't exist."; "lng_language_already" = "You're already using this language pack. You can change your language back at any time in Settings."; "lng_language_not_ready_title" = "Insufficient data"; "lng_language_not_ready_about" = "Unfortunately, this custom language pack ({lang_name}) doesn't contain data for Telegram Desktop. You can contribute to this language pack using the {link}."; "lng_language_not_ready_link" = "translation platform"; "lng_translate_box_error" = "Translate failed."; "lng_translate_box_error_language_pack_not_installed" = "Translation requires a local language pack. Download it in System Settings."; "lng_translate_settings_subtitle" = "Translate Messages"; "lng_translate_settings_show" = "Show Translate Button"; "lng_translate_settings_use_platform_mac" = "Use Apple Translations"; "lng_translate_settings_use_platform_mac_about" = "Translation on macOS won't work until you download local language packs in System Settings."; "lng_translate_settings_use_platform_linux" = "Use KDE's Crow Translate"; "lng_translate_settings_chat" = "Translate Entire Chats"; "lng_translate_settings_choose" = "Do Not Translate"; "lng_translate_settings_about" = "The 'Translate' button will appear in the context menu of messages containing text."; "lng_translate_settings_one" = "Please choose at least one language so that it can be used as the \"Translate to\" language."; "lng_launch_exe_warning" = "This file has the extension {extension}\nIt may harm your computer.\nAre you sure you want to run it?"; "lng_launch_other_warning" = "This file has {extension} extension.\nAre you sure you want to open it?"; "lng_launch_svg_warning" = "Opening this file can potentially expose your IP address to its creator. Continue?"; "lng_launch_exe_sure" = "Run"; "lng_launch_other_sure" = "Open"; "lng_launch_exe_dont_ask" = "Don't ask me again"; "lng_launch_dont_ask" = "Remember for this file type"; "lng_launch_dont_ask_settings" = "You can later edit trusted file types in Settings > Privacy and Security > File open confirmations."; "lng_polls_anonymous" = "Anonymous Poll"; "lng_polls_public" = "Poll"; "lng_polls_anonymous_quiz" = "Anonymous Quiz"; "lng_polls_public_quiz" = "Quiz"; "lng_polls_closed" = "Final results"; "lng_polls_votes_count#one" = "{count} vote"; "lng_polls_votes_count#other" = "{count} votes"; "lng_polls_votes_none" = "No votes"; "lng_polls_answers_count#one" = "{count} answer"; "lng_polls_answers_count#other" = "{count} answers"; "lng_polls_answers_none" = "No answers"; "lng_polls_submit_votes" = "Vote"; "lng_polls_view_results" = "View results"; "lng_polls_view_votes#one" = "View Votes ({count})"; "lng_polls_view_votes#other" = "View Votes ({count})"; "lng_polls_admin_votes#one" = "{count} vote {arrow}"; "lng_polls_admin_votes#other" = "{count} votes {arrow}"; "lng_polls_admin_back_vote" = "{arrow} Vote"; "lng_polls_ends_in_days#one" = "ends in {count} day"; "lng_polls_ends_in_days#other" = "ends in {count} days"; "lng_polls_results_in_days#one" = "results in {count} day"; "lng_polls_results_in_days#other" = "results in {count} days"; "lng_polls_ends_in_time" = "ends in {time}"; "lng_polls_results_in_time" = "results in {time}"; "lng_polls_results_after_close" = "Results will appear after the poll ends."; "lng_polls_retract" = "Retract vote"; "lng_polls_stop" = "Stop poll"; "lng_polls_stop_warning" = "If you stop this poll now, nobody will be able to vote in it anymore. This action cannot be undone."; "lng_polls_stop_sure" = "Stop"; "lng_polls_menu_item" = "Poll"; "lng_polls_create" = "Create poll"; "lng_polls_create_title" = "New poll"; "lng_polls_create_question" = "Question"; "lng_polls_create_question_placeholder" = "Ask a question"; "lng_polls_create_description_placeholder" = "Add Description (optional)"; "lng_polls_create_options" = "Poll options"; "lng_polls_create_option_add" = "Add an option..."; "lng_polls_create_limit#one" = "You can add {count} more option."; "lng_polls_create_limit#other" = "You can add {count} more options."; "lng_polls_create_maximum" = "You have added the maximum number of options."; "lng_polls_create_settings" = "Settings"; "lng_polls_create_show_who_voted" = "Show Who Voted"; "lng_polls_create_show_who_voted_about" = "Display voter name on each option."; "lng_polls_create_allow_multiple_answers" = "Allow Multiple Answers"; "lng_polls_create_allow_multiple_answers_about" = "Voters can select more than one option."; "lng_polls_create_allow_adding_options" = "Allow Adding Options"; "lng_polls_create_allow_adding_options_about" = "Participants can suggest new options."; "lng_polls_create_allow_revoting" = "Allow Revoting"; "lng_polls_create_allow_revoting_about" = "Voters can change their vote."; "lng_polls_create_shuffle_options" = "Shuffle Options"; "lng_polls_create_shuffle_options_about" = "Answers appear in random order for each voter."; "lng_polls_create_set_correct_answer" = "Set Correct Answer"; "lng_polls_create_set_correct_answer_about" = "Mark one option as the right answer."; "lng_polls_create_set_correct_answer_about_multi" = "Mark one or more options as the right answer."; "lng_polls_create_limit_duration" = "Limit Duration"; "lng_polls_create_limit_duration_about" = "Automatically close the poll at a set time."; "lng_polls_create_poll_duration" = "Poll Duration"; "lng_polls_create_poll_ends" = "Poll ends"; "lng_polls_create_hide_results" = "Hide results"; "lng_polls_create_hide_results_about" = "If you switch this on, results will appear only after the poll closes."; "lng_polls_create_duration_custom" = "Custom"; "lng_polls_create_deadline_title" = "Deadline"; "lng_polls_create_deadline_button" = "Set Deadline"; "lng_polls_create_deadline_expired" = "The poll deadline has already passed. Please choose a new time."; "lng_polls_create_anonymous" = "Anonymous Voting"; "lng_polls_create_multiple_choice" = "Multiple Answers"; "lng_polls_create_quiz_mode" = "Quiz Mode"; "lng_polls_create_button" = "Create"; "lng_polls_create_one_answer" = "Quiz has only one right answer."; "lng_polls_choose_question" = "Please enter a question."; "lng_polls_choose_answers" = "Please enter at least two options."; "lng_polls_choose_correct" = "Please choose the correct answer."; "lng_polls_solution_title" = "Explanation"; "lng_polls_solution_placeholder" = "Add a Comment (Optional)"; "lng_polls_solution_about" = "Users will see this comment after choosing a wrong answer, good for educational purposes."; "lng_polls_media_uploading_toast_title" = "Please wait"; "lng_polls_media_uploading_toast" = "Poll media is still uploading..."; "lng_polls_ends_toast" = "Results will appear after the poll ends."; "lng_polls_poll_results_title" = "Poll results"; "lng_polls_quiz_results_title" = "Quiz results"; "lng_polls_show_more#one" = "Show more ({count})"; "lng_polls_show_more#other" = "Show more ({count})"; "lng_polls_votes_collapse" = "Collapse"; "lng_polls_vote_yesterday" = "yesterday"; "lng_polls_option_added_by" = "Added by {user}"; "lng_polls_context_ends" = "Results will appear after the poll ends."; "lng_polls_add_option" = "Add an Option"; "lng_polls_add_option_placeholder" = "Option text..."; "lng_polls_max_options_reached" = "Maximum number of options reached."; "lng_polls_add_option_duplicate" = "This option already exists."; "lng_polls_add_option_closed" = "This poll has been closed."; "lng_polls_add_option_error" = "Could not add the option. Please try again."; "lng_polls_add_option_save" = "Save"; "lng_todo_title" = "Checklist"; "lng_todo_title_group" = "Group Checklist"; "lng_todo_title_user" = "Checklist"; "lng_todo_completed#one" = "{count} of {total} completed"; "lng_todo_completed#other" = "{count} of {total} completed"; "lng_todo_completed_none" = "None of {total} completed"; "lng_todo_menu_item" = "Checklist"; "lng_todo_create" = "Create Checklist"; "lng_todo_create_title" = "New Checklist"; "lng_todo_create_title_placeholder" = "Title"; "lng_todo_create_list" = "Tasks List"; "lng_todo_create_list_add" = "Add a task..."; "lng_todo_create_limit#one" = "You can add {count} more task."; "lng_todo_create_limit#other" = "You can add {count} more tasks."; "lng_todo_create_maximum" = "You have added the maximum number of tasks."; "lng_todo_create_settings" = "Settings"; "lng_todo_create_allow_add" = "Allow Others to Add Tasks"; "lng_todo_create_allow_mark" = "Allow Others to Mark As Done"; "lng_todo_create_button" = "Create"; "lng_todo_choose_title" = "Please enter a title."; "lng_todo_choose_tasks" = "Please enter at least one task."; "lng_todo_add_title" = "Add Tasks"; "lng_todo_create_premium" = "Only subscribers of {link} can create Checklists."; "lng_todo_add_premium" = "Only subscribers of {link} can add tasks."; "lng_todo_mark_premium" = "Only subscribers of {link} can mark tasks as done."; "lng_todo_premium_link" = "Telegram Premium"; "lng_todo_mark_restricted" = "{user} has restricted others from marking tasks as done."; "lng_todo_mark_forwarded" = "You can't change forwarded checklists."; "lng_outdated_title" = "PLEASE UPDATE YOUR OPERATING SYSTEM."; "lng_outdated_title_bits" = "PLEASE SWITCH TO A 64-BIT OPERATING SYSTEM."; "lng_outdated_soon" = "Otherwise, Telegram Desktop will stop updating on {date}."; "lng_outdated_now" = "So Telegram Desktop can update to newer versions."; "lng_screen_reader_bar_text" = "Telegram is working in Screen Reader mode."; "lng_screen_reader_bar_disable" = "Disable"; "lng_screen_reader_confirm_text" = "Telegram detected accessibility software is being used in your system and it is working in Screen Reader friendly mode.\n\nThis may result in unexpected changes to the way Telegram user interface works.\n\nIf you do not use Screen Reader software with Telegram, please disable this mode."; "lng_screen_reader_confirm_disable" = "Disable"; "lng_screen_reader_settings_title" = "Screen reader"; "lng_screen_reader_settings_disable" = "Disable screen reader mode"; "lng_filters_all" = "All chats"; "lng_filters_all_short" = "All"; "lng_filters_setup" = "Edit"; "lng_filters_title" = "Folders"; "lng_filters_subtitle" = "My folders"; "lng_filters_no_chats" = "No chats"; "lng_filters_chats_count#one" = "{count} chat"; "lng_filters_chats_count#other" = "{count} chats"; "lng_filters_create" = "Create new folder"; "lng_filters_about" = "Create folders for different groups of chats and quickly switch between them."; "lng_filters_recommended" = "Recommended folders"; "lng_filters_recommended_add" = "Add"; "lng_filters_restore" = "Undo"; "lng_filters_new" = "New Folder"; "lng_filters_edit" = "Edit Folder"; "lng_filters_setup_menu" = "Edit Folders"; "lng_filters_new_name" = "Folder name"; "lng_filters_enable_animations" = "Enable animations"; "lng_filters_disable_animations" = "Disable animations"; "lng_filters_add_chats" = "Add Chats"; "lng_filters_remove_chats" = "Add Chats to Exclude"; "lng_filters_include" = "Included chats"; "lng_filters_include_about" = "Choose chats or types of chats that will appear in this folder."; "lng_filters_exclude" = "Excluded chats"; "lng_filters_exclude_about" = "Choose chats or types of chats that will not appear in this folder."; "lng_filters_create_button" = "Create"; "lng_filters_include_title" = "Include Chats"; "lng_filters_exclude_title" = "Exclude Chats"; "lng_filters_edit_types" = "Chat types"; "lng_filters_edit_chats" = "Chats"; "lng_filters_include_contacts" = "Contacts"; "lng_filters_include_groups" = "Groups"; "lng_filters_include_channels" = "Channels"; "lng_filters_include_bots" = "Bots"; "lng_filters_name_people" = "People"; "lng_filters_name_unread" = "Unread"; "lng_filters_name_unmuted" = "Unmuted"; "lng_filters_empty" = "Please choose at least one chat for this folder."; "lng_filters_default" = "Please change at least one rule for this folder."; "lng_filters_type_contacts" = "Contacts"; "lng_filters_type_non_contacts" = "Non-Contacts"; "lng_filters_type_groups" = "Groups"; "lng_filters_type_channels" = "Channels"; "lng_filters_type_new" = "New Chats"; "lng_filters_type_existing" = "Existing Chats"; "lng_filters_type_bots" = "Bots"; "lng_filters_type_no_archived" = "Archived"; "lng_filters_type_no_muted" = "Muted"; "lng_filters_type_no_read" = "Read"; "lng_filters_icon_header" = "Choose an icon"; "lng_filters_context_edit" = "Edit folder"; "lng_filters_context_remove" = "Remove"; "lng_filters_remove_sure" = "This will remove the folder, your chats will not be deleted."; "lng_filters_remove_yes" = "Remove"; "lng_filters_menu_add" = "Add to folder"; "lng_filters_toast_add" = "{chat} added to {folder} folder"; "lng_filters_toast_remove" = "{chat} removed from {folder} folder"; "lng_filters_shareable_status" = "shareable folder"; "lng_filters_view_subtitle" = "Tabs view"; "lng_filters_vertical" = "Tabs on the left"; "lng_filters_horizontal" = "Tabs at the top"; "lng_filters_enable_tags" = "Show Folder Tags"; "lng_filters_enable_tags_about" = "Display folder names for each chat in the chat list."; "lng_filters_enable_tags_about_premium" = "Subscribe to **{link}** to display folder names for each chat in the chat list."; "lng_filters_tag_color_subtitle" = "Folder color in chat list"; "lng_filters_tag_color_about" = "Choose a color for the tag of this folder."; "lng_filters_tag_color_no" = "No Tag"; "lng_filters_delete_sure" = "Are you sure you want to delete this folder? This will also deactivate all the invite links created to share this folder."; "lng_filters_link" = "Share Folder"; "lng_filters_link_has" = "Invite links"; "lng_filters_checkbox_remove_bot" = "Remove bot from all folders"; "lng_filters_checkbox_remove_group" = "Remove group from all folders"; "lng_filters_checkbox_remove_channel" = "Remove channel from all folders"; "lng_filters_link_create" = "Create an Invite Link"; "lng_filters_link_cant" = "You can’t share folders which include or exclude specific chat types like 'Groups', 'Contacts', etc."; "lng_filters_link_about" = "Share access to some of this folder's groups and channels with others."; "lng_filters_link_about_many" = "Create more links to set up different access levels for different people."; "lng_filters_link_title" = "Share Folder"; "lng_filters_link_share_about" = "Anyone with this link can add the {folder} folder and the chats selected below."; "lng_filters_link_subtitle" = "Invite link"; "lng_filters_link_chats_none" = "No chats selected"; "lng_filters_link_chats#one" = "{count} chat selected"; "lng_filters_link_chats#other" = "{count} chats selected"; "lng_filters_link_bot_status" = "chats with bots can't be shared"; "lng_filters_link_bot_error" = "Chats with bots can't be shared."; "lng_filters_link_private_status" = "you can't share private chats"; "lng_filters_link_private_error" = "Private chats can't be shared."; "lng_filters_link_noadmin_status" = "you can't invite users here"; "lng_filters_link_noadmin_group_error" = "You don't have the admin rights to share invite links to this private group."; "lng_filters_link_noadmin_channel_error" = "You don't have the admin rights to share invite links to this private channel."; "lng_filters_link_already_group" = "you are already a member"; "lng_filters_link_already_channel" = "you are already subscribed"; "lng_filters_link_inaccessible" = "chat is inaccessible"; "lng_filters_link_chats_about" = "Select groups and channels that you want everyone who adds the folder via invite link to join."; "lng_filters_link_no_about" = "There are no chats in this folder that you can share with others."; "lng_filters_link_chats_no" = "These chats cannot be shared"; "lng_filters_link_chats_no_about" = "You can only share groups and channels in which you are allowed to create invite links."; "lng_filters_link_name_it" = "Name Link"; "lng_filters_link_delete_sure" = "Are you sure you want to delete this link?"; "lng_filters_link_qr_about" = "Anyone on Telegram can scan this code to add the folder and join all the chats included in its invite link."; "lng_filters_link_group_admin_error" = "One of the groups in this folder can’t be added because one of its admins has too many groups and channels."; "lng_filters_by_link_title" = "Add Folder"; "lng_filters_by_link_sure" = "Do you want to add the chat folder {folder} and join its groups and channels?"; "lng_filters_by_link_join#one" = "{count} chat to join"; "lng_filters_by_link_join#other" = "{count} chats to join"; "lng_filters_by_link_add_button" = "Add {folder}"; "lng_filters_by_link_add_no" = "Do not add this folder"; "lng_filters_by_link_more" = "Add Chats to Folder"; "lng_filters_by_link_more_sure" = "Do you want to join chats and add them to the folder {folder}?"; "lng_filters_by_link_about" = "You can deselect the chats you don't want to join."; "lng_filters_by_link_and_join_button#one" = "Join Chat"; "lng_filters_by_link_and_join_button#other" = "Join Chats"; "lng_filters_by_link_join_no" = "Do not join any chats"; "lng_filters_by_link_already" = "Folder already added"; "lng_filters_by_link_already_about" = "You have already added the folder {folder} and all its chats."; "lng_filters_by_link_in#one" = "{count} chat in this folder"; "lng_filters_by_link_in#other" = "{count} chats in this folder"; "lng_filters_by_link_remove" = "Remove Folder"; "lng_filters_by_link_remove_sure" = "Do you also want to quit the chats included in the folder {folder}?"; "lng_filters_by_link_quit#one" = "{count} chat to quit"; "lng_filters_by_link_quit#other" = "{count} chats to quit"; "lng_filters_by_link_select" = "Select All"; "lng_filters_by_link_deselect" = "Deselect All"; "lng_filters_by_link_about_quit" = "You can deselect the chats you don't want to quit."; "lng_filters_by_link_remove_button" = "Remove Folder and Keep Chats"; "lng_filters_by_link_and_quit_button#one" = "Remove Folder and Chat"; "lng_filters_by_link_and_quit_button#other" = "Remove Folder and Chats"; "lng_filters_added_title" = "Folder {folder} Added"; "lng_filters_added_also#one" = "You also joined {count} chat."; "lng_filters_added_also#other" = "You also joined {count} chats."; "lng_filters_updated_title" = "Folder {folder} Updated"; "lng_filters_updated_also#one" = "You have joined {count} new chat."; "lng_filters_updated_also#other" = "You have joined {count} new chats."; "lng_filters_bar_you_can#one" = "You can join {count} new chat"; "lng_filters_bar_you_can#other" = "You can join {count} new chats"; "lng_filters_bar_view#one" = "Click here to view it"; "lng_filters_bar_view#other" = "Click here to view them"; "lng_chat_theme_change" = "Change colors"; "lng_chat_theme_wallpaper" = "Set Wallpaper"; "lng_chat_theme_none" = "No\nTheme"; "lng_chat_theme_apply" = "Apply Theme"; "lng_chat_theme_change_wallpaper" = "Change Wallpaper"; "lng_chat_theme_title" = "Select theme"; "lng_chat_theme_cant_voice" = "Sorry, you can't change the chat theme while you have an unsent voice message."; "lng_chat_theme_gift_replace" = "This gift is already your theme in the chat with {name}. Remove it there and use it here instead?"; "lng_photo_editor_menu_delete" = "Delete"; "lng_photo_editor_menu_flip" = "Flip"; "lng_photo_editor_menu_duplicate" = "Duplicate"; "lng_photo_editor_crop_original" = "Original"; "lng_photo_editor_crop_square" = "Square"; "lng_photo_editor_crop_free" = "Free"; "lng_voice_speed_slow" = "Slow"; "lng_voice_speed_normal" = "Normal"; "lng_voice_speed_medium" = "Medium"; "lng_voice_speed_fast" = "Fast"; "lng_voice_speed_very_fast" = "Very fast"; "lng_voice_speed_super_fast" = "Super fast"; "lng_view_button_user" = "Send message"; "lng_view_button_bot" = "View bot"; "lng_view_button_group" = "View group"; "lng_view_button_channel" = "View channel"; "lng_view_button_bot_app" = "Launch"; "lng_view_button_background" = "View wallpaper"; "lng_view_button_theme" = "View theme"; "lng_view_button_message" = "View message"; "lng_view_button_story" = "View story"; "lng_view_button_voice_chat" = "Video chat"; "lng_view_button_voice_chat_channel" = "Live stream"; "lng_view_button_request_join" = "Request to Join"; "lng_view_button_external_link" = "Open link"; "lng_view_button_boost" = "Boost"; "lng_view_button_giftcode" = "Open"; "lng_view_button_iv" = "Instant View"; "lng_view_button_stickerset" = "View stickers"; "lng_view_button_emojipack" = "View emoji"; "lng_view_button_collectible" = "View collectible"; "lng_view_button_call" = "Join call"; "lng_view_button_storyalbum" = "View Album"; "lng_view_button_collection" = "View Collection"; "lng_view_button_newbot" = "Create Bot"; "lng_sponsored_hide_ads" = "Hide"; "lng_sponsored_title" = "What are sponsored messages?"; "lng_sponsored_info_description1_linked" = "Unlike other apps, Telegram never uses your private data to target ads. {link}\n\nUnlike other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties can’t spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.\n\nTelegram offers free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible advertisers at:"; "lng_sponsored_info_description1_link" = "Learn more in the Privacy Policy"; "lng_sponsored_info_description1_url" = "https://telegram.org/privacy#5-6-no-ads-based-on-user-data"; "lng_sponsored_info_description2" = "Sponsored Messages are currently in test mode. Once they are fully launched and allow Telegram to cover its basic costs, we will start sharing ad revenue with the owners of public channels in which sponsored messages are displayed.\n\nOnline ads should no longer be synonymous with abuse of user privacy. Let us redefine how a tech company should operate – together."; "lng_sponsored_info_menu" = "Advertiser info"; "lng_sponsored_info_submenu" = "Advertiser: {text}"; "lng_sponsored_menu_revenued_about" = "About These Ads"; "lng_sponsored_menu_revenued_report" = "Report Ad"; "lng_sponsored_revenued_subtitle" = "Telegram Ads are very different from ads on other platforms. Ads such as this one:"; "lng_sponsored_revenued_info1_title" = "Respect Your Privacy"; "lng_sponsored_revenued_info1_description" = "Ads on Telegram do not use your personal information and are based on the channel in which you see them."; "lng_sponsored_revenued_info1_bot_description" = "Ads on Telegram do not use your personal information and are based on the mini app in which you see them."; "lng_sponsored_revenued_info1_search_description" = "Ads on Telegram do not use your personal information and are based on the search query you entered."; "lng_sponsored_revenued_info2_title" = "Help the Channel Creator"; "lng_sponsored_revenued_info2_bot_title" = "Help the Bot Developer"; "lng_sponsored_revenued_info2_description" = "50% of the revenue from Telegram Ads goes to the owner of the channel where they are displayed."; "lng_sponsored_revenued_info2_bot_description" = "50% of the revenue from Telegram Ads goes to the developer of the mini app where they are displayed."; "lng_sponsored_revenued_info3_title" = "Can Be Removed"; "lng_sponsored_revenued_info3_description#one" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers."; "lng_sponsored_revenued_info3_description#other" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers."; "lng_sponsored_revenued_info3_bot_description" = "You can turn off ads in mini apps by subscribing to {link}."; "lng_sponsored_revenued_info3_search_description" = "You can turn off ads by subscribing to Telegram Premium. {link}"; "lng_sponsored_revenued_info3_search_link" = "Subscribe {arrow}"; "lng_sponsored_revenued_footer_title" = "Can I Launch an Ad?"; "lng_sponsored_revenued_footer_description" = "Anyone can create an ad to display in this channel — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}"; "lng_sponsored_revenued_footer_bot_description" = "Anyone can create an ad to display in this bot — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}"; "lng_sponsored_revenued_footer_search_description" = "Anyone can create an ad to display in search results for any query. Check out the **Telegram Ad Platform** for details. {link}"; "lng_sponsored_top_bar_hide" = "remove"; "lng_telegram_features_url" = "https://t.me/TelegramTips"; "lng_mini_apps_disclaimer_title" = "Warning"; "lng_mini_apps_disclaimer_text" = "You are about to use a mini app operated by an independent party **not affiliated with Telegram**. You must agree to the Terms of Use for mini apps to continue."; "lng_mini_apps_disclaimer_button" = "I agree to the {link}"; "lng_mini_apps_disclaimer_link" = "Terms of Use"; "lng_mini_apps_tos_url" = "https://telegram.org/tos/mini-apps"; "lng_ringtones_box_title" = "Notification Sound"; "lng_ringtones_box_cloud_subtitle" = "Choose your tone"; "lng_ringtones_box_volume" = "Volume"; "lng_ringtones_box_upload_choose" = "Choose a tone"; "lng_ringtones_box_upload_button" = "Upload Sound"; "lng_ringtones_box_about" = "Right click on any short voice note or MP3 file in chat and select \"Save for Notifications\". It will appear here."; "lng_ringtones_box_default" = "Default"; "lng_ringtones_box_no_sound" = "No sound"; "lng_ringtones_toast_added" = "Sound added!"; "lng_ringtones_error_max_size" = "Sorry, but your file is too big. The maximum size for ringtones is {size}."; "lng_ringtones_error_max_duration" = "Sorry, but your file is too long. The maximum duration for ringtones is {duration}."; "lng_bot_thread_edit" = "Edit Thread"; "lng_bot_thread_title" = "Thread Name"; "lng_bot_thread_choose_title_and_icon" = "Choose a thread name and icon"; "lng_forum_topic_new" = "New Topic"; "lng_forum_topic_edit" = "Edit Topic"; "lng_forum_topic_title" = "Topic Name"; "lng_forum_topic_close" = "Close Topic"; "lng_forum_topic_reopen" = "Reopen Topic"; "lng_forum_topic_closed" = "This topic is closed."; "lng_forum_topic_delete" = "Delete"; "lng_forum_topic_delete_sure" = "Are you sure you want to delete this topic?"; "lng_forum_topic_created_title_my" = "Almost done!"; "lng_forum_topic_created_body_my" = "Send a message to\nstart the topic."; "lng_forum_topic_created_title" = "Topic started!"; "lng_forum_topic_created_body" = "Send a message\nto start the topic."; "lng_forum_topics_switch" = "Topics"; "lng_forum_topics_not_enough#one" = "Only groups with more than **{count} member** can have topics enabled."; "lng_forum_topics_not_enough#other" = "Only groups with more than **{count} members** can have topics enabled."; "lng_forum_topics_no_discussion" = "Topics are not yet available in the discussion groups of channels."; "lng_forum_choose_title_and_icon" = "Choose a topic name and icon"; "lng_forum_replies_only" = "You can reply to messages in topics."; "lng_forum_message_in" = "Message in {topic}"; "lng_forum_reply_in" = "Reply in {topic}"; "lng_forum_no_topics" = "No topics currently created in this group."; "lng_forum_create_topic" = "Create topic"; "lng_forum_discard_sure" = "Are you sure you want to discard this topic?"; "lng_forum_view_as_messages" = "View as Messages"; "lng_forum_view_as_topics" = "View as Topics"; "lng_forum_no_messages" = "No messages"; "lng_forum_messages#one" = "{count} message"; "lng_forum_messages#other" = "{count} messages"; "lng_forum_show_topics_list" = "Show Topics List"; "lng_monoforum_choose_to_reply" = "Choose a message to reply."; "lng_request_peer_requirements" = "Requirements"; "lng_request_peer_rights" = "You must have these admin rights: {rights}."; "lng_request_peer_rights_and" = "{rights} and {last}"; "lng_request_peer_confirm" = "Are you sure you want to send {chat} to {bot}?"; "lng_request_peer_confirm_add" = "This will also add {bot} to {chat}."; "lng_request_peer_confirm_rights" = "This will also add {bot} to {chat} with the following rights: {rights}."; "lng_request_peer_confirm_send" = "Send"; "lng_request_user_title" = "Choose User"; "lng_request_users_title" = "Choose Users"; "lng_request_user_premium_yes" = "The user must have a Premium subscription."; "lng_request_user_premium_no" = "The user must not have a Premium subscription."; "lng_request_user_no" = "No such users"; "lng_request_user_no_about" = "No users found that meet the requirements for this bot."; "lng_request_bot_title" = "Choose a Bot"; "lng_request_bot_no" = "No bots"; "lng_request_bot_no_about" = "You don't have any bots."; "lng_request_group_title" = "Choose a Group"; "lng_request_group_no" = "No such groups"; "lng_request_group_no_about" = "You don't have groups that meet the requirements for this bot."; "lng_request_group_public_yes" = "The group must be public."; "lng_request_group_public_no" = "The group must be private."; "lng_request_group_topics_yes" = "The group must have topics turned on."; "lng_request_group_topics_no" = "The group must have topics turned off."; "lng_request_group_am_owner" = "You must be the owner of the group."; "lng_request_group_change_info" = "change group info"; "lng_request_group_delete_messages" = "delete messages"; "lng_request_group_ban_users" = "ban users"; "lng_request_group_invite" = "invite users via link"; "lng_request_group_pin_messages" = "pin messages"; "lng_request_group_manage_topics" = "manage topics"; "lng_request_group_manage_video_chats" = "manage video chats"; "lng_request_group_anonymous" = "remain anonymous"; "lng_request_group_add_admins" = "add new admins"; "lng_request_group_create" = "Create a New Group for This"; "lng_request_channel_title" = "Choose a Channel"; "lng_request_channel_no" = "No such channels"; "lng_request_channel_no_about" = "You don't have channels that meet the requirements for this bot."; "lng_request_channel_public_yes" = "The channel must be public."; "lng_request_channel_public_no" = "The channel must be private."; "lng_request_channel_am_owner" = "You must be the owner of the channel."; "lng_request_channel_change_info" = "change channel info"; "lng_request_channel_post_messages" = "post messages"; "lng_request_channel_edit_messages" = "edit messages of others"; "lng_request_channel_delete_messages" = "delete messages"; "lng_request_channel_add_subscribers" = "add subscribers"; "lng_request_channel_manage_livestreams" = "manage live streams"; "lng_request_channel_manage_direct" = "manage direct messages"; "lng_request_channel_add_admins" = "add new admins"; "lng_request_channel_create" = "Create a New Channel for This"; "lng_userpic_builder_color_subtitle" = "Choose background"; "lng_userpic_builder_emoji_subtitle" = "Choose sticker or emoji"; "lng_stories_my_name" = "My Story"; "lng_stories_archive" = "Hide Stories"; "lng_stories_unarchive" = "Unhide Stories"; "lng_stories_view_anonymously" = "View Anonymously"; "lng_stories_row_count#one" = "{count} Story"; "lng_stories_row_count#other" = "{count} Stories"; "lng_stories_views#one" = "{count} view"; "lng_stories_views#other" = "{count} views"; "lng_stories_no_views" = "No views yet"; "lng_stories_view_reactions" = "View reactions"; "lng_stories_unsupported" = "This story is not supported\nby your version of Telegram."; "lng_stories_cant_reply" = "You can't reply to this story."; "lng_stories_about_silent" = "This video has no sound."; "lng_stories_about_close_friends" = "You are seeing this story because {user} added you to their list of **Close Friends**."; "lng_stories_about_contacts" = "Only {user}'s contacts can view this story."; "lng_stories_about_selected_contacts" = "Only some users {user} selected can view this story."; "lng_stories_about_close_friends_my" = "Only people from your **Close Friends** list can view this story."; "lng_stories_about_contacts_my" = "Only your contacts can view this story."; "lng_stories_about_selected_contacts_my" = "Only some users you selected can view this story."; "lng_stories_click_to_view_mine" = "Click here to view your story."; "lng_stories_click_to_view" = "Click here to view updates from {users}."; "lng_stories_click_to_view_and_one" = "{accumulated}, {user}"; "lng_stories_click_to_view_and_last" = "{accumulated} and {user}"; "lng_stories_show_more" = "Show more"; "lng_stories_my_title" = "Posted Stories"; "lng_stories_archive_button" = "Story Archive"; "lng_stories_recent_button" = "Recent Stories"; "lng_stories_archive_title" = "Story Archive"; "lng_stories_archive_about" = "Only you can see archived stories unless you choose to post them to your profile."; "lng_stories_channel_archive_about" = "Only admins of the channel can see archived stories unless they are posted to the channel page."; "lng_stories_empty" = "Your stories will be here."; "lng_stories_empty_channel" = "Channel posts will be here."; "lng_stories_reply_sent" = "Message sent."; "lng_stories_hidden_to_contacts" = "Stories from {user} were moved to the **Archive**."; "lng_stories_shown_in_chats" = "Stories from {user} were returned from the **Archive**."; "lng_stories_delete_one_sure" = "Are you sure you want to delete this story?"; "lng_stories_delete_sure#one" = "Are you sure you want to delete {count} story?"; "lng_stories_delete_sure#other" = "Are you sure you want to delete {count} stories?"; "lng_stories_save_sure" = "Do you want to post this story on your profile?"; "lng_stories_save_sure_many#one" = "Do you want to post {count} story to your profile?"; "lng_stories_save_sure_many#other" = "Do you want to post {count} stories to your profile?"; "lng_stories_save_done" = "Story posted to your profile."; "lng_stories_save_done_many#one" = "{count} story is posted on your profile."; "lng_stories_save_done_many#other" = "{count} stories are posted on your profile."; "lng_stories_save_done_about" = "Posted stories can be viewed by others on your profile until you remove them."; "lng_stories_archive_sure" = "Do you want to hide this story from your profile?"; "lng_stories_archive_sure_many#one" = "Do you want to remove {count} story from your profile?"; "lng_stories_archive_sure_many#other" = "Do you want to remove {count} stories from your profile?"; "lng_stories_archive_done" = "This story is hidden from your profile."; "lng_stories_archive_done_many#one" = "{count} story is hidden from your profile."; "lng_stories_archive_done_many#other" = "{count} stories are hidden from your profile."; "lng_stories_channel_save_sure" = "Do you want to post this story to the channel page?"; "lng_stories_channel_save_sure_many#one" = "Do you want to post {count} story to the channel page?"; "lng_stories_channel_save_sure_many#other" = "Do you want to post {count} stories to the channel page?"; "lng_stories_channel_save_done" = "This story is posted to the channel page."; "lng_stories_channel_save_done_many#one" = "{count} story posted to the channel page."; "lng_stories_channel_save_done_many#other" = "{count} stories posted to the channel page."; "lng_stories_channel_save_done_about" = "Posted stories can be viewed by others on the channel page until an admin removes them."; "lng_stories_channel_archive_sure" = "Do you want to hide this story from the channel page?"; "lng_stories_channel_archive_sure_many#one" = "Do you want to hide {count} story from the channel page?"; "lng_stories_channel_archive_sure_many#other" = "Do you want to hide {count} stories from the channel page?"; "lng_stories_channel_archive_done" = "This story is hidden from the channel page."; "lng_stories_channel_archive_done_many#one" = "{count} story is hidden from the channel page."; "lng_stories_channel_archive_done_many#other" = "{count} stories are hidden from the channel page."; "lng_stories_save_promo" = "Subscribe to {link} to save other people's stories that are not protected."; "lng_stories_reaction_as_message" = "Send reaction as a private message"; "lng_stories_album_add" = "Add Album"; "lng_stories_album_new_title" = "Create a New Album"; "lng_stories_album_new_button" = "New Album"; "lng_stories_album_new_text" = "Choose a name for your album and start adding your stories there."; "lng_stories_album_new_ph" = "Title"; "lng_stories_album_new_create" = "Create"; "lng_stories_album_empty_title" = "Organize Your Stories"; "lng_stories_album_empty_text" = "Add some of your stories to this album."; "lng_stories_album_all" = "All Stories"; "lng_stories_album_add_title" = "Add Stories"; "lng_stories_album_add_button" = "Add Stories"; "lng_stories_album_share" = "Share Album"; "lng_stories_album_edit" = "Edit Name"; "lng_stories_album_limit_title" = "Limit Reached"; "lng_stories_album_limit_text" = "Please remove one of the existing albums to add a new one."; "lng_stories_album_delete" = "Delete Album"; "lng_stories_album_delete_sure" = "Are you sure you want to delete this album?"; "lng_stories_album_delete_button" = "Delete"; "lng_stories_album_add_to" = "Add to Album"; "lng_stealth_mode_menu_item" = "Hide My View"; "lng_stealth_mode_title" = "Stealth Mode"; "lng_stealth_mode_unlock_about" = "Subscribe to Telegram Premium to watch stories without appearing in the list of viewers."; "lng_stealth_mode_about" = "Turn Stealth Mode on to watch stories without appearing in the list of viewers."; "lng_stealth_mode_past_title" = "Hide Recent Views"; "lng_stealth_mode_past_about" = "Hide my views from the past 5 minutes."; "lng_stealth_mode_next_title" = "Hide Upcoming Views"; "lng_stealth_mode_next_about" = "Hide my views for the next 25 minutes."; "lng_stealth_mode_unlock" = "Unlock Stealth Mode"; "lng_stealth_mode_enable" = "Enable Stealth Mode"; "lng_stealth_mode_enable_and_open" = "Enable and open the story"; "lng_stealth_mode_cooldown_in" = "Available in {left}"; "lng_stealth_mode_cooldown_tip" = "Please wait until **Stealth Mode** is ready to use again."; "lng_stealth_mode_enabled_tip_title" = "Stealth Mode On"; "lng_stealth_mode_enabled_tip" = "The creators of stories you viewed in the last **5 minutes** or will view in the next **25 minutes** won't see you in the viewers' lists."; "lng_stealth_mode_countdown" = "Stealth Mode active – {left}"; "lng_stealth_mode_already_title" = "You are in Stealth Mode"; "lng_stealth_mode_already_about" = "The creators of stories you view in the next **{left}** won't see you in the viewers' lists."; "lng_stories_link_invalid" = "This link is broken or has expired."; "lng_stories_live_finished" = "The live story has ended."; "lng_stats_title" = "Statistics"; "lng_stats_message_title" = "Message Statistic"; "lng_stats_story_title" = "Story Statistic"; "lng_stats_zoom_out" = "Zoom Out"; "lng_stats_day_month_year" = "{days_count} {month} {year}"; "lng_stats_day_month" = "{days_count} {month}"; "lng_stats_weekday_day_month_year" = "{day}, {days_count} {month} {year}"; "lng_stats_weekday_day_month_time" = "{day}, {days_count} {month} {time}"; "lng_stats_overview_title" = "Overview"; "lng_stats_overview_member_count" = "Followers"; "lng_stats_overview_mean_view_count" = "Views Per Post"; "lng_stats_overview_mean_share_count" = "Shares Per Post"; "lng_stats_overview_mean_reactions_count" = "Reactions Per Post"; "lng_stats_overview_mean_story_view_count" = "Views Per Story"; "lng_stats_overview_mean_story_share_count" = "Shares Per Story"; "lng_stats_overview_mean_story_reactions_count" = "Reactions Per Story"; "lng_stats_overview_enabled_notifications" = "Enabled Notifications"; "lng_stats_overview_messages" = "Messages"; "lng_stats_overview_group_mean_view_count" = "Viewing Members"; "lng_stats_overview_group_mean_post_count" = "Posting Members"; "lng_stats_overview_message_private_shares" = "Private Shares"; "lng_stats_overview_message_public_shares" = "Public Shares"; "lng_stats_overview_message_views" = "Views"; "lng_stats_overview_message_public_share#one" = "{count} public share"; "lng_stats_overview_message_public_share#other" = "{count} public shares"; "lng_stats_members_title" = "Top members"; "lng_stats_admins_title" = "Top admins"; "lng_stats_inviters_title" = "Top inviters"; "lng_stats_member_messages#one" = "{count} message"; "lng_stats_member_messages#other" = "{count} messages"; "lng_stats_member_characters#one" = "{count} symbol per message"; "lng_stats_member_characters#other" = "{count} symbols per message"; "lng_stats_member_deletions#one" = "{count} deletion"; "lng_stats_member_deletions#other" = "{count} deletions"; "lng_stats_member_bans#one" = "{count} ban"; "lng_stats_member_bans#other" = "{count} bans"; "lng_stats_member_restrictions#one" = "{count} restriction"; "lng_stats_member_restrictions#other" = "{count} restrictions"; "lng_stats_member_invitations#one" = "{count} invitation"; "lng_stats_member_invitations#other" = "{count} invitations"; "lng_stats_recent_messages_title" = "Recent posts"; "lng_stats_recent_messages_views#one" = "{count} view"; "lng_stats_recent_messages_views#other" = "{count} views"; "lng_stats_loading" = "Loading stats..."; "lng_stats_loading_subtext" = "Please wait a few moments while we generate your stats."; "lng_stats_boosts_loading" = "Loading boosts list..."; "lng_stats_boosts_loading_subtext" = "Please wait a few moments while we generate your stats."; "lng_stats_earn_loading" = "Loading rewards info..."; "lng_stats_earn_loading_subtext" = "Please wait a few moments while we generate your stats."; "lng_chart_title_member_count" = "Growth"; "lng_chart_title_join" = "Followers"; "lng_chart_title_mute" = "Notifications"; "lng_chart_title_view_count_by_hour" = "Views by hours (UTC)"; "lng_chart_title_view_count_by_source" = "Views by source"; "lng_chart_title_join_by_source" = "New followers by source"; "lng_chart_title_language" = "Languages"; "lng_chart_title_message_interaction" = "Interactions"; "lng_chart_title_instant_view_interaction" = "IV Interactions"; "lng_chart_title_reactions_by_emotion" = "Reactions"; "lng_chart_title_story_interactions" = "Story Interactions"; "lng_chart_title_story_reactions_by_emotion" = "Story reactions"; "lng_chart_title_group_join" = "Group members"; "lng_chart_title_group_join_by_source" = "New members by source"; "lng_chart_title_group_language" = "Members's primary language"; "lng_chart_title_group_message_content" = "Messages"; "lng_chart_title_group_action" = "Actions"; "lng_chart_title_group_day" = "Views by hours"; "lng_chart_title_group_week" = "Top days of week"; "lng_boosts_title" = "Boosts"; "lng_boosts_level" = "Level"; "lng_boosts_existing" = "Existing boosts"; "lng_boosts_premium_audience" = "Premium subscribers"; "lng_boosts_premium_members" = "Premium members"; "lng_boosts_next_level" = "Boosts to level up"; "lng_boosts_list_title#one" = "{count} boost"; "lng_boosts_list_title#other" = "{count} boosts"; "lng_boosts_list_subtext" = "Your channel is currently boosted by these users."; "lng_boosts_list_subtext_group" = "Your group is currently boosted by these users."; "lng_boosts_show_more_boosts#one" = "Show {count} More Boosts"; "lng_boosts_show_more_boosts#other" = "Show {count} More Boosts"; "lng_boosts_show_more_gifts#one" = "Show {count} More Boosts"; "lng_boosts_show_more_gifts#other" = "Show {count} More Boosts"; "lng_boosts_list_status" = "boost expires on {date}"; "lng_boosts_link_title" = "Link for boosting"; "lng_boosts_link_subtext" = "Share this link with your subscribers to get more boosts."; "lng_boosts_link_subtext_group" = "Share this link with the members of your group to get more boosts."; "lng_boosts_get_boosts" = "Get Boosts via Gifts"; "lng_boosts_get_boosts_subtext" = "Get more boosts for your channel by gifting Telegram Premium to your subscribers."; "lng_boosts_get_boosts_subtext_group" = "Get more boosts for your group by gifting Telegram Premium to the members."; "lng_boosts_list_unclaimed" = "Unclaimed"; "lng_boosts_list_pending" = "To be distributed"; "lng_boosts_list_pending_about" = "The recipient will be selected when the giveaway ends."; "lng_boosts_list_tab_gifts#one" = "{count} Gift"; "lng_boosts_list_tab_gifts#other" = "{count} Gifts"; "lng_boosts_prepaid_giveaway_title" = "Prepaid giveaways"; "lng_boosts_prepaid_giveaway_title_subtext" = "Select a giveaway you already paid for to set it up."; "lng_boosts_prepaid_giveaway_single" = "Prepaid giveaway"; "lng_boosts_prepaid_giveaway_quantity#one" = "{count} Telegram Premium"; "lng_boosts_prepaid_giveaway_quantity#other" = "{count} Telegram Premium"; "lng_boosts_prepaid_giveaway_moths#one" = "{count}-month subscriptions"; "lng_boosts_prepaid_giveaway_moths#other" = "{count}-month subscriptions"; "lng_boosts_prepaid_giveaway_status#one" = "{count} subscription {duration}"; "lng_boosts_prepaid_giveaway_status#other" = "{count} subscriptions {duration}"; "lng_boosts_prepaid_giveaway_credits_status#one" = "{amount} among {count} winner."; "lng_boosts_prepaid_giveaway_credits_status#other" = "{amount} among {count} winners."; "lng_channel_earn_title" = "Monetization"; "lng_channel_earn_about" = "Telegram shares 50% of the revenue from ads displayed in your channel as rewards. {link}"; "lng_channel_earn_about_bot" = "Telegram shares 50% of the revenue from ads displayed in your bot. {link}"; "lng_channel_earn_about_link" = "Learn more {emoji}"; "lng_channel_earn_overview_title" = "Rewards overview"; "lng_channel_earn_available" = "Rewards available for collection"; "lng_channel_earn_reward" = "Rewards since last collection"; "lng_channel_earn_total" = "Total lifetime rewards"; "lng_channel_earn_balance_title" = "Available reward"; "lng_channel_earn_balance_button" = "Collect"; "lng_channel_earn_balance_password_title" = "Two-step verification"; "lng_channel_earn_balance_password_description" = "Please enter your password to collect."; "lng_channel_earn_balance_about" = "Collect your reward using Fragment, a third-party platform used by advertisers to pay for ads. {link}"; "lng_channel_earn_balance_about_temp" = "In the coming weeks you will be able to collect your reward using Fragment, a third-party platform used by advertisers to pay ads. {link}"; "lng_channel_earn_transfer_sure_about1" = "Check the address of the recipient:"; "lng_channel_earn_transfer_sure_about2" = "This action can not be undone. If the address above is incorrect you will lose your TON."; "lng_channel_earn_history_title" = "Transaction history"; "lng_channel_earn_history_in" = "Rewards from ads"; "lng_channel_earn_history_in_about" = "Rewards from ads displayed in"; "lng_channel_earn_history_out" = "Collection"; "lng_channel_earn_history_out_failed" = "Not Completed"; "lng_channel_earn_history_out_about_failed" = "Couldn't collect reward"; "lng_channel_earn_history_out_button" = "View in Blockchain Explorer"; "lng_channel_earn_history_return" = "Refund"; "lng_channel_earn_history_return_about" = "Refunded back"; "lng_channel_earn_history_pending" = "Pending"; "lng_channel_earn_history_failed" = "Failed"; "lng_channel_earn_history_show_more#one" = "Show {count} More Transaction"; "lng_channel_earn_history_show_more#other" = "Show {count} More Transactions"; "lng_channel_earn_off" = "Switch Off Ads"; "lng_channel_earn_off_about" = "You will not be eligible for any rewards if you switch off ads."; "lng_channel_earn_cpm_min" = "No Ads"; "lng_channel_earn_cpm#one" = "{emoji} {count} CPM"; "lng_channel_earn_cpm#other" = "{emoji} {count} CPM"; "lng_channel_earn_learn_title" = "Earn From Your Channel"; "lng_channel_earn_bot_learn_title" = "Earn From Your Bot"; "lng_channel_earn_learn_in_subtitle" = "Telegram Ads"; "lng_channel_earn_learn_in_about" = "Telegram can display ads in your channel."; "lng_channel_earn_learn_bot_in_about" = "Telegram can display ads in your bot."; "lng_channel_earn_learn_split_subtitle" = "50:50 revenue split"; "lng_channel_earn_learn_split_about" = "You can receive 50% of the ad revenue as rewards in TON."; "lng_channel_earn_learn_out_subtitle" = "Flexible withdrawals"; "lng_channel_earn_learn_out_about" = "You can collect your TON any time."; "lng_channel_earn_learn_coin_title" = "What is {emoji} TON?"; "lng_channel_earn_learn_coin_about" = "TON is a blockchain platform and cryptocurrency that Telegram uses for its high speed and low commissions on transactions. {link}"; "lng_channel_earn_learn_close" = "Got it"; "lng_channel_earn_learn_coin_link" = "https://telegram.org/blog/monetization-for-channels"; "lng_channel_earn_chart_top_hours" = "Ad impressions"; "lng_channel_earn_chart_revenue" = "Ad rewards"; "lng_channel_earn_chart_overriden_detail_credits" = "Rewards in Stars"; "lng_channel_earn_chart_overriden_detail_currency" = "Rewards in TON"; "lng_channel_earn_chart_overriden_detail_usd" = "Rewards in USD"; "lng_channel_earn_currency_history" = "TON Transactions"; "lng_channel_earn_credits_history" = "Stars Transactions"; "lng_channel_earn_out_check_password_about" = "You can withdraw only if you have:"; "lng_bot_earn_title" = "Stars Balance"; "lng_bot_earn_chart_revenue" = "Revenue"; "lng_bot_earn_overview_title" = "Proceeds overview"; "lng_bot_earn_available" = "Available balance"; "lng_bot_earn_reward" = "Total balance"; "lng_bot_earn_total" = "Total lifetime proceeds"; "lng_bot_earn_balance_title" = "Available balance"; "lng_bot_earn_balance_about" = "Stars from your total balance can be used for ads or withdrawn as rewards 21 days after they are earned."; "lng_bot_earn_balance_about_url" = "https://telegram.org/tos/stars"; "lng_bot_earn_balance_button#one" = "Withdraw {emoji} {count}"; "lng_bot_earn_balance_button#other" = "Withdraw {emoji} {count}"; "lng_bot_earn_balance_button_all" = "Withdraw all stars"; "lng_bot_earn_balance_button_locked" = "Withdraw"; "lng_bot_earn_balance_button_buy_ads" = "Buy Ads"; "lng_bot_earn_learn_credits_out_about" = "You can withdraw Stars using Fragment, or use Stars to advertise your bot. {link}"; "lng_self_earn_learn_credits_out_about" = "You can withdraw from 10 Stars using Fragment. {link}"; "lng_bot_earn_out_ph" = "Enter amount to withdraw"; "lng_bot_earn_out_ph_max" = "Enter amount to withdraw (max. {amount})"; "lng_bot_earn_balance_password_title" = "Two-step verification"; "lng_bot_earn_balance_password_description" = "Please enter your password to collect."; "lng_bot_earn_credits_out_minimal" = "You cannot withdraw less than {link}."; "lng_bot_earn_credits_out_minimal_link#one" = "{count} star"; "lng_bot_earn_credits_out_minimal_link#other" = "{count} stars"; "lng_bot_copy_text_tooltip" = "Copy to Clipboard: {text}"; "lng_contact_add" = "Add"; "lng_contact_send_message" = "Message"; "lng_iv_open_in_browser" = "Open in Browser"; "lng_iv_share" = "Share"; "lng_iv_join_channel" = "Join"; "lng_iv_window_title" = "Instant View"; "lng_iv_wrong_layout" = "Wrong layout?"; "lng_iv_not_supported" = "This link appears to be invalid."; "lng_iv_zoom_tooltip_ctrl" = "Hold Ctrl to zoom by 5%.\nHold Alt to zoom by 1%."; "lng_iv_zoom_tooltip_cmd" = "Hold Cmd to zoom by 5%.\nHold Alt to zoom by 1%."; "lng_limit_download_title" = "Download speed limited"; "lng_limit_download_subscribe" = "Subscribe to {link} to increase download speed {increase}."; "lng_limit_download_increase_times#one" = "**{count}** time"; "lng_limit_download_increase_times#other" = "**{count}** times"; "lng_limit_download_increase_speed" = "by **{percent}**"; "lng_limit_download_subscribe_link" = "Telegram Premium"; "lng_limit_upload_title" = "Upload speed limited"; "lng_limit_upload_subscribe" = "Subscribe to {link} to increase upload speed {increase}."; "lng_limit_upload_increase_times#one" = "**{count}** time"; "lng_limit_upload_increase_times#other" = "**{count}** times"; "lng_limit_upload_increase_speed" = "by **{percent}**"; "lng_limit_upload_subscribe_link" = "Telegram Premium"; "lng_recent_frequent" = "Frequent contacts"; "lng_recent_frequent_all" = "Show all"; "lng_recent_frequent_collapse" = "Collapse"; "lng_recent_title" = "Recent"; "lng_recent_clear" = "Clear"; "lng_recent_clear_sure" = "Do you want to clear your search history?"; "lng_recent_remove" = "Remove from Recent"; "lng_recent_clear_all" = "Clear all"; "lng_recent_hide_top" = "Remove all & Disable"; "lng_recent_hide_sure" = "Are you sure you want to clear and disable frequent contacts list?\n\nYou can always turn this feature back on in Settings > Privacy > Suggest Frequent Contacts."; "lng_recent_hide_button" = "Hide"; "lng_recent_none" = "Recent search results\nwill appear here."; "lng_recent_chats" = "Chats"; "lng_recent_channels" = "Channels"; "lng_recent_apps" = "Apps"; "lng_recent_posts" = "Posts"; "lng_all_photos" = "Photos"; "lng_all_videos" = "Videos"; "lng_all_downloads" = "Downloads"; "lng_all_links" = "Links"; "lng_all_files" = "Files"; "lng_all_music" = "Music"; "lng_all_voice" = "Voice"; "lng_channels_none_title" = "No channels yet..."; "lng_channels_none_about" = "You are not currently subscribed to any channels."; "lng_channels_your_title" = "Channels you joined"; "lng_channels_your_more" = "Show more"; "lng_channels_your_less" = "Show less"; "lng_channels_recommended" = "Similar channels"; "lng_bot_apps_your" = "Apps you use"; "lng_bot_apps_popular" = "Grossing apps"; "lng_bot_apps_which" = "Which apps are included here? {link}"; "lng_bot_apps_which_link" = "Learn >"; "lng_posts_title" = "Global Search"; "lng_posts_start" = "Type a keyword to search all posts from public channels."; "lng_posts_subscribe" = "Subscribe to Premium"; "lng_posts_need_subscribe" = "Global search is a Premium feature."; "lng_posts_search_button" = "Search {query}"; "lng_posts_remaining#one" = "{count} free search remaining today"; "lng_posts_remaining#other" = "{count} free searches remaining today"; "lng_posts_subtitle_empty" = "Telegram News"; "lng_posts_subtitle" = "Public posts"; "lng_posts_limit_reached" = "Limit Reached"; "lng_posts_limit_about#one" = "You can make up to {count} search query per day."; "lng_posts_limit_about#other" = "You can make up to {count} search queries per day."; "lng_posts_limit_search_paid" = "Search for {cost}"; "lng_posts_limit_unlocks" = "free search unlocks in {duration}"; "lng_posts_paid_spent#one" = "**{count} Star** spent on extra search."; "lng_posts_paid_spent#other" = "**{count} Stars** spent on extra search."; "lng_popular_apps_info_title" = "Top Mini Apps"; "lng_popular_apps_info_text" = "This catalogue ranks mini apps based on their daily revenue, measured in Stars. To be listed, developers must set their main mini apps in {bot} (as described {link}), have over **1,000** daily users, and earn a daily revenue above **1,000** Stars, based on the weekly average."; "lng_popular_apps_info_bot" = "@botfather"; "lng_popular_apps_info_here" = "here"; "lng_popular_apps_info_url" = "https://core.telegram.org/bots/webapps#launching-the-main-mini-app"; "lng_popular_apps_info_confirm" = "Understood"; "lng_font_box_title" = "Choose font family"; "lng_font_default" = "Default"; "lng_font_system" = "System font"; "lng_font_not_found" = "Font not found."; "lng_search_tab_my_messages" = "My Messages"; "lng_search_tab_this_topic" = "This Topic"; "lng_search_tab_this_chat" = "This Chat"; "lng_search_tab_this_channel" = "This Channel"; "lng_search_tab_this_group" = "This Group"; "lng_search_tab_public_posts" = "Public Posts"; "lng_search_tab_no_results" = "No Results"; "lng_search_tab_no_results_text" = "There were no results for \"{query}\"."; "lng_search_tab_no_results_retry" = "Try another hashtag."; "lng_search_tab_by_hashtag" = "Enter a hashtag to find messages containing it."; "lng_search_tab_try_in_all" = "Search in All Messages"; "lng_contact_details_button" = "View Contact"; "lng_contact_details_title" = "Contact details"; "lng_contact_details_phone" = "Phone"; "lng_contact_details_phone_main" = "Main Phone"; "lng_contact_details_phone_home" = "Home Phone"; "lng_contact_details_phone_mobile" = "Mobile Phone"; "lng_contact_details_phone_work" = "Work Phone"; "lng_contact_details_phone_other" = "Other Phone"; "lng_contact_details_email" = "Email"; "lng_contact_details_address" = "Address"; "lng_contact_details_url" = "URL"; "lng_contact_details_note" = "Note"; "lng_contact_details_birthday" = "Birthday"; "lng_contact_details_organization" = "Organization"; "lng_qr_box_quality" = "Quality"; "lng_qr_box_quality1" = "Normal"; "lng_qr_box_quality2" = "High"; "lng_qr_box_quality3" = "Very High"; "lng_qr_box_transparent_background" = "Transparent Background"; "lng_qr_box_font_size" = "Font size"; "lng_frozen_bar_title" = "Your account is frozen!"; "lng_frozen_bar_text" = "Click to view details {arrow}"; "lng_frozen_restrict_title" = "Your account is frozen"; "lng_frozen_restrict_text" = "Click to view details"; "lng_frozen_title" = "Your Account is Frozen"; "lng_frozen_subtitle1" = "Violation of Terms"; "lng_frozen_text1" = "Your account was frozen for breaking Telegram's Terms and Conditions."; "lng_frozen_subtitle2" = "Read-Only Mode"; "lng_frozen_text2" = "You can access your account but can't send messages or take actions."; "lng_frozen_subtitle3" = "Appeal Before Deactivation"; "lng_frozen_text3" = "Appeal via {link} before {date}, or your account will be deleted."; "lng_frozen_appeal_button" = "Submit an Appeal"; "lng_age_verify_title" = "Age Verification"; "lng_age_verify_mobile" = "Please open this media in the official Telegram app for Android or iOS to verify your age."; "lng_age_verify_here" = "This is a one-time process using your phone's camera. Your selfie will not be stored by Telegram."; "lng_age_verify_button" = "Verify My Age"; "lng_age_verify_sorry_title" = "Age Check Failed"; "lng_age_verify_sorry_text" = "Sorry, you can't view 18+ content."; "lng_context_bank_card_copy" = "Copy Card Number"; "lng_context_bank_card_copied" = "Card number copied to clipboard."; "lng_summarize_header_title" = "AI summary"; "lng_summarize_header_about" = "Click to see original text"; "lng_calendar" = "Calendar"; "lng_new_window_tooltip_ctrl" = "Use Ctrl+Click to open in New Window."; "lng_new_window_tooltip_cmd" = "Use Cmd+Click to open in New Window."; "lng_rename_file" = "Rename file"; "lng_sr_playback_order" = "Playback order"; "lng_sr_player_close" = "Close media player"; "lng_sr_group_call_menu" = "Video chat menu"; "lng_sr_search_date" = "Search by date"; "lng_sr_cancel_search" = "Cancel search"; "lng_sr_clear_search" = "Clear search"; "lng_sr_scroll_to_top" = "Scroll to top"; "lng_sr_verified_badge" = "Verified"; "lng_sr_bot_verified_badge" = "Verified Bot"; "lng_sr_profile_menu" = "Profile menu"; "lng_sr_close_panel" = "Close panel"; "lng_ai_compose_title" = "AI Editor"; "lng_ai_compose_apply" = "Apply"; "lng_ai_compose_tab_translate" = "Translate"; "lng_ai_compose_tab_style" = "Style"; "lng_ai_compose_tab_fix" = "Fix"; "lng_ai_compose_original" = "Original"; "lng_ai_compose_result" = "Result"; "lng_ai_compose_to_language" = "To {language}"; "lng_ai_compose_name_style" = "{name} ({style})"; "lng_ai_compose_style_neutral" = "Neutral"; "lng_ai_compose_emojify" = "emojify"; "lng_ai_compose_error" = "AI request failed."; "lng_ai_compose_tooltip" = "Rewrite, translate, or correct your text using AI."; "lng_ai_compose_flood_title" = "Daily limit reached"; "lng_ai_compose_flood_text" = "Get {link} for **50x** more AI text transformations per day."; "lng_ai_compose_flood_link" = "Telegram Premium"; "lng_ai_compose_increase_limit" = "Increase Limit"; "lng_ai_compose_select_style" = "Select Style"; "lng_ai_compose_apply_style" = "Apply Style"; "lng_ai_compose_style_tooltip" = "Choose Style"; "lng_send_as_file_tooltip" = "Send text as a file."; // Wnd specific "lng_wnd_choose_program_menu" = "Choose Default Program..."; "lng_wnd_menu_undo" = "Undo"; "lng_wnd_menu_redo" = "Redo"; // Linux specific "lng_linux_menu_undo" = "Undo"; "lng_linux_menu_redo" = "Redo"; "lng_linux_menu_tools" = "Tools"; "lng_linux_menu_help" = "Help"; "lng_linux_no_audio_prefs" = "You don't have any audio configuration applications installed."; // Mac specific "lng_mac_choose_program_menu" = "Other..."; "lng_mac_choose_app" = "Choose Application"; "lng_mac_choose_text" = "Choose an application to open the document \"{file}\"."; "lng_mac_enable_filter" = "Show:"; "lng_mac_recommended_apps" = "Recommended Applications"; "lng_mac_all_apps" = "All Applications"; "lng_mac_always_open_with" = "Always Open With"; "lng_mac_this_app_can_open" = "This application can open \"{file}\"."; "lng_mac_not_known_app" = "It's not known if this application can open \"{file}\"."; "lng_mac_menu_services" = "Services"; "lng_mac_menu_hide_telegram" = "Hide {telegram}"; "lng_mac_menu_hide_others" = "Hide Others"; "lng_mac_menu_show_all" = "Show All"; "lng_mac_menu_preferences" = "Preferences..."; "lng_mac_menu_quit_telegram" = "Quit {telegram}"; "lng_mac_menu_about_telegram" = "About {telegram}"; //"lng_mac_menu_warn_before_quit" = "Warn Before Quitting ({text})"; "lng_mac_menu_file" = "File"; "lng_mac_menu_logout" = "Log Out"; "lng_mac_menu_edit" = "Edit"; "lng_mac_menu_undo" = "Undo"; "lng_mac_menu_redo" = "Redo"; "lng_mac_menu_cut" = "Cut"; "lng_mac_menu_copy" = "Copy"; "lng_mac_menu_paste" = "Paste"; "lng_mac_menu_delete" = "Delete"; "lng_mac_menu_select_all" = "Select All"; "lng_mac_menu_window" = "Window"; "lng_mac_menu_contacts" = "Contacts"; "lng_mac_menu_add_contact" = "Add Contact"; "lng_mac_menu_new_group" = "New Group"; "lng_mac_menu_new_channel" = "New Channel"; "lng_mac_menu_show" = "Show Telegram"; "lng_mac_menu_emoji_and_symbols" = "Emoji & Symbols"; "lng_mac_menu_fullscreen" = "Toggle Full Screen"; "lng_mac_menu_player_pause" = "Pause"; "lng_mac_menu_player_resume" = "Resume"; "lng_mac_menu_player_next" = "Next"; "lng_mac_menu_player_previous" = "Previous"; "lng_mac_menu_profiles" = "Profiles"; "lng_mac_touchbar_favorite_stickers" = "Favorite stickers"; "lng_mac_hold_to_quit" = "Hold {text} to Quit"; // Keys finished ================================================ FILE: Telegram/Resources/langs/nl.lproj/Localizable.strings ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ ================================================ FILE: Telegram/Resources/langs/pt-BR.lproj/Localizable.strings ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ ================================================ FILE: Telegram/Resources/langs/refresh.py ================================================ import os, sys, requests, re from os.path import expanduser filename = '' for arg in sys.argv: if re.match(r'.*\.strings$', arg): filename = expanduser(arg) result = '' if not os.path.isfile(filename): print("File not found.") sys.exit(1) with open(filename) as f: for line in f: if re.match(r'\s*\/\* new from [a-zA-Z0-9\.]+ \*\/\s*', line): continue if re.match(r'\"lng_[a-z_]+\#(zero|two|few|many)\".+', line): continue result = result + line remove = 0 while (len(result) > remove + 1) and (result[len(result) - remove - 1] == '\n') and (result[len(result) - remove - 2] == '\n'): remove = remove + 1 result = result[:len(result) - remove] with open('lang.strings', 'w') as out: out.write(result) sys.exit() ================================================ FILE: Telegram/Resources/langs/refresh.sh ================================================ set -e FullExecPath=$PWD pushd `dirname $0` > /dev/null FullScriptPath=`pwd` popd > /dev/null FileName="$1" if [ ! -d "$FullScriptPath/../../../../DesktopPrivate" ]; then echo "" echo "This script is for building the production version of Telegram Desktop." echo "" echo "For building custom versions please visit the build instructions page at:" echo "https://github.com/telegramdesktop/tdesktop/#build-instructions" exit fi Error () { cd $FullExecPath echo "$1" exit 1 } if [ ! -f "$FileName" ]; then Error "File '$FileName' not found." fi cd "$FullScriptPath" python refresh.py $FileName ================================================ FILE: Telegram/Resources/langs/stale.py ================================================ import os, sys, requests, re os.chdir() keys = [] with open('lang.strings') as f: for line in f: m = re.match(r'\"(lng_[a-z_]+)(\#[a-z]+)?\"', line) if m: keys.append(m.group(1)) elif not re.match(r'^\s*$', line): print('Bad line: ' + line) sys.exit(1) print('Keys: ' + str(len(keys))) sys.exit() ================================================ FILE: Telegram/Resources/numbers.txt ================================================ 1876;JM;Jamaica;1876 XXX XXXX;11; 1869;KN;Saint Kitts & Nevis;1869 XXX XXXX;11; 1868;TT;Trinidad & Tobago;1868 XXX XXXX;11; 1784;VC;Saint Vincent & the Grenadines;1784 XXX XXXX;11; 1767;DM;Dominica;1767 XXX XXXX;11; 1758;LC;Saint Lucia;1758 XXX XXXX;11; 1721;SX;Sint Maarten;1721 XXX XXXX;11; 1684;AS;American Samoa;1684 XXX XXXX;11; 1671;GU;Guam;1671 XXX XXXX;11; 1670;MP;Northern Mariana Islands;1670 XXX XXXX;11; 1664;MS;Montserrat;1664 XXX XXXX;11; 1649;TC;Turks & Caicos Islands;1649 XXX XXXX;11; 1473;GD;Grenada;1473 XXX XXXX;11; 1441;BM;Bermuda;1441 XXX XXXX;11; 1345;KY;Cayman Islands;1345 XXX XXXX;11; 1340;VI;US Virgin Islands;1340 XXX XXXX;11; 1284;VG;British Virgin Islands;1284 XXX XXXX;11; 1268;AG;Antigua & Barbuda;1268 XXX XXXX;11; 1264;AI;Anguilla;1264 XXX XXXX;11; 1246;BB;Barbados;1246 XXX XXXX;11; 1242;BS;Bahamas;1242 XXX XXXX;11; 998;UZ;Uzbekistan;998 XX XXXXXXX;12; 996;KG;Kyrgyzstan 995;GE;Georgia 994;AZ;Azerbaijan;994 XX XXX XX XX;12; 993;TM;Turkmenistan;993 XX XXXXXX;11; 992;TJ;Tajikistan 977;NP;Nepal 976;MN;Mongolia 975;BT;Bhutan 974;QA;Qatar 973;BH;Bahrain;973 XXXX XXXX;11; 972;IL;Israel;972 XX XXX XXXX;12; 971;AE;United Arab Emirates;971 XX XXX XXXX;12; 970;PS;Palestine;970 XXX XX XXXX;12; 968;OM;Oman;968 XXXX XXXX;11; 967;YE;Yemen;967 XXX XXX XXX;12; 966;SA;Saudi Arabia; 965;KW;Kuwait;965 XXXX XXXX;11; 964;IQ;Iraq;964 XXX XXX XXXX;13; 963;SY;Syria 962;JO;Jordan;962 X XXXX XXXX;12; 961;LB;Lebanon 960;MV;Maldives 886;TW;Taiwan 880;BD;Bangladesh 856;LA;Laos 855;KH;Cambodia 853;MO;Macau 852;HK;Hong Kong 850;KP;North Korea 692;MH;Marshall Islands 691;FM;Micronesia 690;TK;Tokelau 689;PF;French Polynesia 688;TV;Tuvalu 687;NC;New Caledonia 686;KI;Kiribati 685;WS;Samoa 683;NU;Niue 682;CK;Cook Islands 681;WF;Wallis & Futuna 680;PW;Palau 679;FJ;Fiji 678;VU;Vanuatu 677;SB;Solomon Islands 676;TO;Tonga 675;PG;Papua New Guinea 674;NR;Nauru 673;BN;Brunei Darussalam;673 XXX XXXX;10; 672;NF;Norfolk Island 670;TL;Timor-Leste 599;BQ;Bonaire, Sint Eustatius & Saba 599;CW;Curaçao 598;UY;Uruguay;598 XXXX XXXX;11; 597;SR;Suriname;597 XXX XXXX;10; 596;MQ;Martinique 595;PY;Paraguay;595 XXX XXX XXX;12; 594;GF;French Guiana 593;EC;Ecuador 592;GY;Guyana 591;BO;Bolivia;591 X XXX XXXX;11; 590;GP;Guadeloupe 509;HT;Haiti 508;PM;Saint Pierre & Miquelon 507;PA;Panama;507 XXXX XXXX;11; 506;CR;Costa Rica 505;NI;Nicaragua;505 XXXX XXXX;11; 504;HN;Honduras;504 XXXX XXXX;11; 503;SV;El Salvador;503 XXXX XXXX;11; 502;GT;Guatemala;502 X XXX XXXX;11; 501;BZ;Belize 500;FK;Falkland Islands 423;LI;Liechtenstein 421;SK;Slovakia 420;CZ;Czech Republic 389;MK;Macedonia 387;BA;Bosnia & Herzegovina 386;SI;Slovenia 385;HR;Croatia 383;XK;Kosovo;383 XXXX XXXX;11; 382;ME;Montenegro 381;RS;Serbia;381 XX XXX XXXX;12; 380;UA;Ukraine;380 XX XXX XX XX;12; 378;SM;San Marino;378 XXX XXX XXXX;13; 377;MC;Monaco;377 XXXX XXXX;11; 376;AD;Andorra;376 XX XX XX;9; 375;BY;Belarus;375 XX XXX XXXX;12; 374;AM;Armenia;374 XX XXX XXX;11; 373;MD;Moldova;373 XX XXX XXX;11; 372;EE;Estonia; 371;LV;Latvia;371 XXX XXXXX;11; 370;LT;Lithuania;370 XXX XXXXX;11; 359;BG;Bulgaria; 358;FI;Finland; 357;CY;Cyprus;357 XXXX XXXX;11; 356;MT;Malta;356 XX XX XX XX;11; 355;AL;Albania;355 XX XXX XXXX;12; 354;IS;Iceland;354 XXX XXXX;10; 353;IE;Ireland;353 XX XXX XXXX;12; 352;LU;Luxembourg 351;PT;Portugal;351 X XXXX XXXX;12; 350;GI;Gibraltar;350 XXXX XXXX;11; 299;GL;Greenland;299 XXX XXX;9; 298;FO;Faroe Islands;298 XXX XXX;9; 297;AW;Aruba;297 XXX XXXX;10; 291;ER;Eritrea;291 X XXX XXX;10; 290;SH;Saint Helena;290 XX XXX;8; 269;KM;Comoros;269 XXX XXXX;10; 268;SZ;Swaziland;268 XXXX XXXX;11; 267;BW;Botswana;267 XX XXX XXX;11; 266;LS;Lesotho;266 XX XXX XXX;11; 265;MW;Malawi 264;NA;Namibia;264 XX XXX XXXX;12; 263;ZW;Zimbabwe;263 XX XXX XXXX;12; 262;RE;Réunion;262 XXX XXX XXX;12; 261;MG;Madagascar;261 XX XX XXX XX;12; 260;ZM;Zambia;260 XX XXX XXXX;12; 258;MZ;Mozambique;258 XX XXX XXXX;12; 257;BI;Burundi;257 XX XX XXXX;11; 256;UG;Uganda;256 XX XXX XXXX;12; 255;TZ;Tanzania;255 XX XXX XXXX;12; 254;KE;Kenya;254 XXX XXX XXX;12; 253;DJ;Djibouti;253 XX XX XX XX;11; 252;SO;Somalia;252 XX XXX XXX;11; 251;ET;Ethiopia;251 XX XXX XXXX;12; 250;RW;Rwanda;250 XXX XXX XXX;12; 249;SD;Sudan;249 XX XXX XXXX;12; 248;SC;Seychelles;248 X XX XX XX;10; 247;SH;Saint Helena;247 XXXX;7; 246;IO;Diego Garcia;246 XXX XXXX;10; 245;GW;Guinea-Bissau;245 XXX XXXX;10; 244;AO;Angola;244 XXX XXX XXX;12; 243;CD;Congo (Dem. Rep.);243 XX XXX XXXX;12; 242;CG;Congo (Rep.);242 XX XXX XXXX;12; 241;GA;Gabon;241 X XX XX XX;10; 240;GQ;Equatorial Guinea;240 XXX XXX XXX;12; 239;ST;São Tomé & Príncipe;239 XX XXXXX;10; 238;CV;Cape Verde;238 XXX XXXX;10; 237;CM;Cameroon;237 XXXX XXXX;11; 236;CF;Central African Rep.;236 XX XX XX XX;11; 235;TD;Chad;235 XX XX XX XX;11; 234;NG;Nigeria 233;GH;Ghana 232;SL;Sierra Leone;232 XX XXX XXX;11; 231;LR;Liberia; 230;MU;Mauritius; 229;BJ;Benin;229 XX XXX XXX;11; 228;TG;Togo;228 XX XXX XXX;11; 227;NE;Niger;227 XX XX XX XX;11; 226;BF;Burkina Faso;226 XX XX XX XX;11; 225;CI;Côte d`Ivoire;225 XX XXX XXX;11; 224;GN;Guinea;224 XXX XXX XXX;12; 223;ML;Mali;223 XXXX XXXX;11; 222;MR;Mauritania;222 XXXX XXXX;11; 221;SN;Senegal;221 XX XXX XXXX;12; 220;GM;Gambia;220 XXX XXXX;10; 218;LY;Libya;218 XX XXX XXXX;12; 216;TN;Tunisia;216 XX XXX XXX;11; 213;DZ;Algeria;213 XXX XX XX XX;12; 212;MA;Morocco;212 XX XXX XXXX;12; 211;SS;South Sudan;211 XX XXX XXXX;12; 98;IR;Iran;98 XXX XXX XXXX;12; 95;MM;Myanmar; 94;LK;Sri Lanka;94 XX XXX XXXX;11; 93;AF;Afghanistan;93 XXX XXX XXX;11; 92;PK;Pakistan;92 XXX XXX XXXX;12; 91;IN;India;91 XXXXX XXXXX;12; 90;TR;Turkey;90 XXX XXX XXXX;12 86;CN;China;86 XXX XXXX XXXX;13; 84;VN;Vietnam; 82;KR;South Korea; 81;JP;Japan;81 XX XXXX XXXX;12; 66;TH;Thailand;66 X XXXX XXXX;11; 65;SG;Singapore;65 XXXX XXXX;10; 64;NZ;New Zealand; 63;PH;Philippines;63 XXX XXX XXXX;12; 62;ID;Indonesia; 61;AU;Australia;61 XXX XXX XXX;11; 60;MY;Malaysia; 58;VE;Venezuela;58 XXX XXX XXXX;12; 57;CO;Colombia;57 XXX XXX XXXX;12; 56;CL;Chile;56 X XXXX XXXX;11; 55;BR;Brazil;55 XX XXXXX XXXX;13; 54;AR;Argentina; 53;CU;Cuba;53 XXXX XXXX;10; 52;MX;Mexico; 51;PE;Peru;51 XXX XXX XXX;11; 49;DE;Germany; 48;PL;Poland;48 XXX XXX XXX;11; 47;NO;Norway;47 XXXX XXXX;10; 46;SE;Sweden;46 XX XXX XXXX;11; 45;DK;Denmark;45 XXXX XXXX;10; 44;GB;United Kingdom;44 XXXX XXXXXX;12; 43;AT;Austria; 41;CH;Switzerland;41 XX XXX XXXX;11; 40;RO;Romania;40 XXX XXX XXX;11; 39;IT;Italy;39 XXX XXX XXXX;12; 36;HU;Hungary;36 XX XXX XXXX;11; 34;ES;Spain;34 XXX XXX XXX;11; 33;FR;France;33 X XX XX XX XX;11; 32;BE;Belgium;32 XXX XX XX XX;11; 31;NL;Netherlands;31 X XX XX XX XX;11; 30;GR;Greece;30 XX XXXX XXXX;12; 27;ZA;South Africa;27 XX XXX XXXX;11; 20;EG;Egypt;20 XX XXX XXXX;11; 7;RU;Russian Federation;7 XXX XXX XX XX;11; 7;KZ;Kazakhstan;7 XXX XXX XX XX;11 1;US;USA;1 XXX XXX XXXX;11; 1;PR;Puerto Rico;1 XXX XXX XXXX;11; 1;DO;Dominican Rep.;1 XXX XXX XXXX;11; 1;CA;Canada;1 XXX XXX XXXX;11; ================================================ FILE: Telegram/Resources/picker_html/picker.css ================================================ :root { --font-sans: -apple-system, BlinkMacSystemFont, avenir next, avenir, Segoe UI Variable Text, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, tahoma, arial, sans-serif; } html { width: 100%; height: 100%; padding: 0; margin: 0; } body { font-family: var(--font-sans); width: 100%; height: 100%; padding: 0; margin: 0; background-color: var(--td-window-bg); color: var(--td-window-fg); } html.custom_scroll ::-webkit-scrollbar { border-radius: 5px !important; border: 3px solid transparent !important; background-color: var(--td-scroll-bg) !important; background-clip: content-box !important; width: 10px !important; } html.custom_scroll ::-webkit-scrollbar:hover { background-color: var(--td-scroll-bg-over) !important; } html.custom_scroll ::-webkit-scrollbar-thumb { border-radius: 5px !important; border: 3px solid transparent !important; background-color: var(--td-scroll-bar-bg) !important; background-clip: content-box !important; } html.custom_scroll ::-webkit-scrollbar-thumb:hover { background-color: var(--td-scroll-bar-bg-over) !important; } #map { position: relative; width: 100%; height: 100%; } #marker { pointer-events: none; display: none; z-index: 2; position: absolute; width: 100%; height: 100%; justify-content: center; align-items: center; } #marker_drop { margin-bottom: 0px; transition: margin 160ms ease-in-out; } #marker_drop.moving { margin-bottom: 24px; } #marker_shadow { position: absolute; } #search_venues { position: absolute; left: 50%; transform: translateX(-50%); z-index: 2; top: -30px; transition: top 200ms ease-in-out; } #search_venues.shown { top: 6px; } #search_venues_inner { position: relative; overflow: hidden; font-size: 13px; font-weight: 500; background: var(--td-window-bg); color: var(--td-window-active-text-fg); cursor: pointer; border-radius: 14px; padding: 5px 12px 6px; box-shadow: 0 0 3px 0px var(--td-history-to-down-shadow); } #search_venues_inner:hover { background: var(--td-window-bg-over); } #search_venues_content { position: relative; z-index: 2; } #search_venues_content:before { content: var(--td-lng-maps-places-in-area); } #search_venues_inner .ripple .inner { position: absolute; border-radius: 50%; transform: scale(0); opacity: 1; animation: ripple 650ms cubic-bezier(0.22, 1, 0.36, 1) forwards; background-color: var(--td-window-bg-ripple); } #search_venues_inner .ripple.hiding { animation: fadeOut 200ms linear forwards; } @keyframes ripple { to { transform: scale(2); } } @keyframes fadeOut { to { opacity: 0; } } ================================================ FILE: Telegram/Resources/picker_html/picker.js ================================================ var LocationPicker = { startZoom: 14, flySpeed: 2.4, notify: function(message) { if (window.external && window.external.invoke) { window.external.invoke(JSON.stringify(message)); } }, frameKeyDown: function (e) { const keyW = (e.key === 'w') || (e.code === 'KeyW') || (e.keyCode === 87); const keyQ = (e.key === 'q') || (e.code === 'KeyQ') || (e.keyCode === 81); const keyM = (e.key === 'm') || (e.code === 'KeyM') || (e.keyCode === 77); if ((e.metaKey || e.ctrlKey) && (keyW || keyQ || keyM)) { e.preventDefault(); LocationPicker.notify({ event: 'keydown', modifier: e.ctrlKey ? 'ctrl' : 'cmd', key: keyW ? 'w' : keyQ ? 'q' : 'm', }); } else if (e.key === 'Escape' || e.keyCode === 27) { e.preventDefault(); LocationPicker.notify({ event: 'keydown', key: 'escape', }); } }, isNight: function() { var html = document.getElementsByTagName('html')[0]; return html.style.getPropertyValue('--td-night') == '1'; }, lightPreset: function() { return LocationPicker.isNight() ? 'night' : 'day'; }, updateStyles: function (styles) { if (LocationPicker.styles !== styles) { LocationPicker.styles = styles; document.getElementsByTagName('html')[0].style = styles; LocationPicker.map.setConfigProperty( 'basemap', 'lightPreset', LocationPicker.lightPreset()); } }, init: function (params) { mapboxgl.accessToken = params.token; if (location.hostname != 'desktop-app-resource') { mapboxgl.config.API_URL = location.protocol + '//' + location.host + '/api.mapbox.com'; } var options = { container: 'map', config: { basemap: { lightPreset: LocationPicker.lightPreset() } } }; var center = params.center; if (center) { center = [center[1], center[0]]; options.center = center; options.zoom = LocationPicker.startZoom; } else if (params.bounds) { options.bounds = params.bounds; center = new mapboxgl.LngLatBounds(params.bounds).getCenter(); } else { center = [0, 0]; } LocationPicker.map = new mapboxgl.Map(options); LocationPicker.createMarker(center); LocationPicker.trackMovement(); LocationPicker.initSearchVenueRipple(); }, marker: function() { return document.getElementById('marker_drop'); }, createMarker: function(center) { document.getElementById('marker').style.display = 'flex'; }, clearMovingTimer: function() { if (LocationPicker.clearMovingTimeoutId) { clearTimeout(LocationPicker.clearMovingTimeoutId); LocationPicker.clearMovingTimeoutId = 0; } }, startMovingTimer: function(done) { LocationPicker.clearMovingTimer(); LocationPicker.clearMovingTimeoutId = setTimeout(done, 500); }, trackMovement: function() { LocationPicker.map.on('movestart', function() { LocationPicker.marker().classList.add('moving'); LocationPicker.clearMovingTimer(); LocationPicker.toggleSearchVenues(false); LocationPicker.notify({ event: 'move_start' }); }); LocationPicker.map.on('moveend', function() { LocationPicker.startMovingTimer(function() { LocationPicker.marker().classList.remove('moving'); LocationPicker.notify({ event: 'move_end', latitude: LocationPicker.map.getCenter().lat, longitude: LocationPicker.map.getCenter().lng }); }); }); }, narrowTo: function (point) { LocationPicker.map.flyTo({ center: [point[1], point[0]], zoom: LocationPicker.startZoom, speed: LocationPicker.flySpeed, }); }, send: function () { LocationPicker.notify({ event: 'send', latitude: LocationPicker.map.getCenter().lat, longitude: LocationPicker.map.getCenter().lng }); }, addRipple: function (button, x, y) { const ripple = document.createElement('span'); ripple.classList.add('ripple'); const inner = document.createElement('span'); inner.classList.add('inner'); var rect = button.getBoundingClientRect(); x -= rect.x; y -= rect.y; const mx = button.clientWidth - x; const my = button.clientHeight - y; const sq1 = x * x + y * y; const sq2 = mx * mx + y * y; const sq3 = x * x + my * my; const sq4 = mx * mx + my * my; const radius = Math.sqrt(Math.max(sq1, sq2, sq3, sq4)); inner.style.width = inner.style.height = `${2 * radius}px`; inner.style.left = `${x - radius}px`; inner.style.top = `${y - radius}px`; inner.classList.add('inner'); ripple.addEventListener('animationend', function (e) { if (e.animationName === 'fadeOut') { ripple.remove(); } }); ripple.appendChild(inner); button.appendChild(ripple); }, stopRipples: function (button) { const id = button.id ? button.id : button; button = document.getElementById(id); const ripples = button.getElementsByClassName('ripple'); for (var i = 0; i < ripples.length; ++i) { const ripple = ripples[i]; if (!ripple.classList.contains('hiding')) { ripple.classList.add('hiding'); } } }, initSearchVenueRipple: function() { var button = document.getElementById('search_venues_inner'); button.addEventListener('mousedown', function (e) { LocationPicker.addRipple(e.currentTarget, e.clientX, e.clientY); LocationPicker.searchVenuesPressed = true; }); button.addEventListener('mouseup', function (e) { const id = e.currentTarget.id; setTimeout(function () { LocationPicker.stopRipples(id); }, 0); if (LocationPicker.searchVenuesPressed) { LocationPicker.searchVenuesPressed = false; LocationPicker.toggleSearchVenues(false); LocationPicker.notify({ event: 'search_venues', latitude: LocationPicker.map.getCenter().lat, longitude: LocationPicker.map.getCenter().lng }); } }); button.addEventListener('mouseleave', function (e) { LocationPicker.stopRipples(e.currentTarget); LocationPicker.searchVenuesPressed = false; }); }, toggleSearchVenues: function(shown) { var button = document.getElementById('search_venues'); button.classList.toggle('shown', shown); }, }; ================================================ FILE: Telegram/Resources/qrc/emoji_1.qrc ================================================ ../emoji/emoji_1.webp ================================================ FILE: Telegram/Resources/qrc/emoji_2.qrc ================================================ ../emoji/emoji_2.webp ================================================ FILE: Telegram/Resources/qrc/emoji_3.qrc ================================================ ../emoji/emoji_3.webp ================================================ FILE: Telegram/Resources/qrc/emoji_4.qrc ================================================ ../emoji/emoji_4.webp ================================================ FILE: Telegram/Resources/qrc/emoji_5.qrc ================================================ ../emoji/emoji_5.webp ================================================ FILE: Telegram/Resources/qrc/emoji_6.qrc ================================================ ../emoji/emoji_6.webp ================================================ FILE: Telegram/Resources/qrc/emoji_7.qrc ================================================ ../emoji/emoji_7.webp ================================================ FILE: Telegram/Resources/qrc/emoji_8.qrc ================================================ ../emoji/emoji_8.webp ================================================ FILE: Telegram/Resources/qrc/emoji_preview.qrc ================================================ ../emoji/set0_preview.webp ../emoji/set1_preview.webp ../emoji/set2_preview.webp ../emoji/set3_preview.webp ================================================ FILE: Telegram/Resources/qrc/telegram/animations.qrc ================================================ ../../animations/blocked_peers_empty.tgs ../../animations/change_number.tgs ../../animations/filters.tgs ../../animations/cloud_filters.tgs ../../animations/local_passcode_enter.tgs ../../animations/cloud_password/intro.tgs ../../animations/cloud_password/password_input.tgs ../../animations/cloud_password/hint.tgs ../../animations/cloud_password/email.tgs ../../animations/cloud_password/validate.tgs ../../animations/ttl.tgs ../../animations/discussion.tgs ../../animations/stats.tgs ../../animations/stats_boosts.tgs ../../animations/stats_earn.tgs ../../animations/voice_ttl_idle.tgs ../../animations/voice_ttl_start.tgs ../../animations/chat/voice_to_video.tgs ../../animations/chat/video_to_voice.tgs ../../animations/chat/sparkles_emoji.tgs ../../animations/chat/white_flag_emoji.tgs ../../animations/palette.tgs ../../animations/sleep.tgs ../../animations/greeting.tgs ../../animations/location.tgs ../../animations/robot.tgs ../../animations/writing.tgs ../../animations/hours.tgs ../../animations/phone.tgs ../../animations/chat_link.tgs ../../animations/diamond.tgs ../../animations/collectible_username.tgs ../../animations/collectible_phone.tgs ../../animations/search.tgs ../../animations/noresults.tgs ../../animations/hello_status.tgs ../../animations/starref_link.tgs ../../animations/media_forbidden.tgs ../../animations/edit_peers/topics.tgs ../../animations/edit_peers/topics_tabs.tgs ../../animations/edit_peers/topics_list.tgs ../../animations/edit_peers/direct_messages.tgs ../../animations/no_chats.tgs ../../animations/transcribe_loading.tgs ../../animations/cake.tgs ../../animations/camera_outline.tgs ../../animations/photo_suggest_icon.tgs ../../animations/toast/saved_messages.tgs ../../animations/toast/tagged.tgs ../../animations/my_gifts_empty.tgs ../../animations/toast/chats_filter_in.tgs ../../animations/rtmp.tgs ../../animations/show_or_premium_lastseen.tgs ../../animations/show_or_premium_readtime.tgs ../../animations/passkeys.tgs ../../animations/ban.tgs ../../animations/cocoon.tgs ../../animations/craft_failed.tgs ../../animations/stop.tgs ../../icons/poll/toast_hide_results.tgs ../../icons/poll/uploading.tgs ../../animations/profile/profile_muting.tgs ../../animations/profile/profile_unmuting.tgs ../../animations/dice/dice_idle.tgs ../../animations/dice/dart_idle.tgs ../../animations/dice/bball_idle.tgs ../../animations/dice/fball_idle.tgs ../../animations/dice/slot_0_idle.tgs ../../animations/dice/slot_1_idle.tgs ../../animations/dice/slot_2_idle.tgs ../../animations/dice/slot_back.tgs ../../animations/dice/slot_pull.tgs ../../animations/dice/winners.tgs ../../animations/dice/dice_6.tgs ../../animations/star_reaction/appear.tgs ../../animations/star_reaction/center.tgs ../../animations/star_reaction/select.tgs ../../animations/star_reaction/toast.tgs ../../animations/star_reaction/effect1.tgs ../../animations/star_reaction/effect2.tgs ../../animations/star_reaction/effect3.tgs ../../animations/photo_editor/pen.tgs ../../animations/photo_editor/arrow.tgs ../../animations/photo_editor/marker.tgs ../../animations/photo_editor/eraser.tgs ../../animations/photo_editor/blur.tgs ../../animations/swipe_action/archive.tgs ../../animations/swipe_action/unarchive.tgs ../../animations/swipe_action/delete.tgs ../../animations/swipe_action/disabled.tgs ../../animations/swipe_action/mute.tgs ../../animations/swipe_action/unmute.tgs ../../animations/swipe_action/pin.tgs ../../animations/swipe_action/unpin.tgs ../../animations/swipe_action/read.tgs ../../animations/swipe_action/unread.tgs ../../animations/craft_progress.tgs ================================================ FILE: Telegram/Resources/qrc/telegram/export.qrc ================================================ ../../export_html/css/style.css ../../export_html/images/back.png ../../export_html/images/back@2x.png ../../export_html/images/media_call.png ../../export_html/images/media_call@2x.png ../../export_html/images/media_contact.png ../../export_html/images/media_contact@2x.png ../../export_html/images/media_file.png ../../export_html/images/media_file@2x.png ../../export_html/images/media_game.png ../../export_html/images/media_game@2x.png ../../export_html/images/media_location.png ../../export_html/images/media_location@2x.png ../../export_html/images/media_music.png ../../export_html/images/media_music@2x.png ../../export_html/images/media_photo.png ../../export_html/images/media_photo@2x.png ../../export_html/images/media_shop.png ../../export_html/images/media_shop@2x.png ../../export_html/images/media_video.png ../../export_html/images/media_video@2x.png ../../export_html/images/media_voice.png ../../export_html/images/media_voice@2x.png ../../export_html/images/section_calls.png ../../export_html/images/section_calls@2x.png ../../export_html/images/section_chats.png ../../export_html/images/section_chats@2x.png ../../export_html/images/section_contacts.png ../../export_html/images/section_contacts@2x.png ../../export_html/images/section_frequent.png ../../export_html/images/section_frequent@2x.png ../../export_html/images/section_music.png ../../export_html/images/section_music@2x.png ../../export_html/images/section_other.png ../../export_html/images/section_other@2x.png ../../export_html/images/section_photos.png ../../export_html/images/section_photos@2x.png ../../export_html/images/section_sessions.png ../../export_html/images/section_sessions@2x.png ../../export_html/images/section_stories.png ../../export_html/images/section_stories@2x.png ../../export_html/images/section_web.png ../../export_html/images/section_web@2x.png ../../export_html/js/script.js ================================================ FILE: Telegram/Resources/qrc/telegram/iv.qrc ================================================ ../../iv_html/page.css ../../iv_html/page.js ../../iv_html/highlight.9.12.0.css ../../iv_html/highlight.9.12.0.js ../../iv_html/morphdom-umd.min.2.7.2.js ================================================ FILE: Telegram/Resources/qrc/telegram/mac_icons.qrc ================================================ ../../art/icon_round512@2x.png ================================================ FILE: Telegram/Resources/qrc/telegram/picker.qrc ================================================ ../../picker_html/picker.css ../../picker_html/picker.js ================================================ FILE: Telegram/Resources/qrc/telegram/sounds.qrc ================================================ ../../sounds/msg_incoming.mp3 ../../sounds/call_busy.mp3 ../../sounds/call_connect.mp3 ../../sounds/call_end.mp3 ../../sounds/call_incoming.mp3 ../../sounds/call_outgoing.mp3 ../../sounds/group_call_start.mp3 ../../sounds/group_call_connect.mp3 ../../sounds/group_call_end.mp3 ../../sounds/group_call_allowed.mp3 ../../sounds/group_call_recording_start.mp3 ================================================ FILE: Telegram/Resources/qrc/telegram/telegram.qrc ================================================ ../../art/background.tgv ../../art/bg_thumbnail.png ../../art/bg_initial.jpg ../../art/business_logo.png ../../art/affiliate_logo.png ../../art/logo_256.png ../../art/logo_256_square.png ../../art/logo_256_no_margin.png ../../art/forkgram/logo_256.png ../../art/forkgram/logo_256_no_margin.png ../../art/themeimage.jpg ../../art/round_placeholder.jpg ../../art/cocoon.webp ../../day-blue.tdesktop-theme ../../night.tdesktop-theme ../../night-green.tdesktop-theme ../../day-custom-base.tdesktop-theme ../../night-custom-base.tdesktop-theme ../../icons/calls/hands.lottie ../../icons/calls/voice.lottie ../../art/recording/recording_info_audio.svg ../../art/recording/recording_info_video_landscape.svg ../../art/recording/recording_info_video_portrait.svg ../../art/ttl/video_message_icon.svg ../../icons/settings/dino.svg ../../icons/settings/star.svg ../../icons/settings/starmini.svg ../../icons/tray_monochrome.svg ../../icons/tray_monochrome_attention.svg ../../icons/tray_monochrome_mute.svg ../../art/topic_icons/blue.svg ../../art/topic_icons/yellow.svg ../../art/topic_icons/violet.svg ../../art/topic_icons/green.svg ../../art/topic_icons/rose.svg ../../art/topic_icons/red.svg ../../art/topic_icons/gray.svg ../../art/topic_icons/general.svg ../../icons/info/edit/links_subscription.svg ../../icons/plane_white.svg ../../art/dice/dice1.svg ../../art/dice/dice2.svg ../../art/dice/dice3.svg ../../art/dice/dice4.svg ../../art/dice/dice5.svg ../../art/dice/dice6.svg ../../icons/calls/hands.lottie ../../icons/calls/voice.lottie ../../icons/settings/devices/device_desktop_mac.lottie ../../icons/settings/devices/device_desktop_win.lottie ../../icons/settings/devices/device_linux.lottie ../../icons/settings/devices/device_linux_ubuntu.lottie ../../icons/settings/devices/device_phone_android.lottie ../../icons/settings/devices/device_phone_ios.lottie ../../icons/settings/devices/device_tablet_ios.lottie ../../icons/settings/devices/device_web_chrome.lottie ../../icons/settings/devices/device_web_edge.lottie ../../icons/settings/devices/device_web_firefox.lottie ../../icons/settings/devices/device_web_safari.lottie ../../default_shortcuts-custom.json ../../../../lib/xdg/org.telegram.desktop.desktop ================================================ FILE: Telegram/Resources/qrc/telegram.qrc ================================================ ================================================ FILE: Telegram/Resources/uwp/AppX/AppxManifest.xml ================================================ Telegram Desktop Telegram Messenger LLP Telegram Desktop official messenger Assets\logo\logo.png ================================================ FILE: Telegram/Resources/uwp/priconfig.xml ================================================ ================================================ FILE: Telegram/Resources/winrc/Telegram.manifest ================================================  true/pm PerMonitor UTF-8 ================================================ FILE: Telegram/Resources/winrc/Telegram.rc ================================================ // Microsoft Visual C++ generated resource script. // #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #if defined(__MINGW64__) || defined(__MINGW32__) // MinGW-w64, MinGW #if defined(__has_include) && __has_include() #include #else #include #include #endif #else // MSVC, Windows SDK #include #endif ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON1 ICON "..\\art\\icon256.ico" ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 6,7,6,0 PRODUCTVERSION 6,7,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "" VALUE "FileDescription", "Telegram Desktop" VALUE "FileVersion", "6.7.6.0" VALUE "LegalCopyright", "Copyright (C) 2014-2026" VALUE "ProductName", "Telegram Desktop" VALUE "ProductVersion", "6.7.6.0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// ================================================ FILE: Telegram/Resources/winrc/Updater.rc ================================================ // Microsoft Visual C++ generated resource script. // #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #if defined(__MINGW64__) || defined(__MINGW32__) // MinGW-w64, MinGW #if defined(__has_include) && __has_include() #include #else #include #include #endif #else // MSVC, Windows SDK #include #endif ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 6,7,6,0 PRODUCTVERSION 6,7,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "" VALUE "FileDescription", "Telegram Desktop Updater" VALUE "FileVersion", "6.7.6.0" VALUE "LegalCopyright", "Copyright (C) 2014-2026" VALUE "ProductName", "Telegram Desktop" VALUE "ProductVersion", "6.7.6.0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// ================================================ FILE: Telegram/SourceFiles/_other/packer.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "packer.h" bool BetaChannel = false; quint64 AlphaVersion = 0; bool OnlyAlphaKey = false; const char *PublicKey = "\ -----BEGIN RSA PUBLIC KEY-----\n\ MIGJAoGBAMA4ViQrjkPZ9xj0lrer3r23JvxOnrtE8nI69XLGSr+sRERz9YnUptnU\n\ BZpkIfKaRcl6XzNJiN28cVwO1Ui5JSa814UAiDHzWUqCaXUiUEQ6NmNTneiGx2sQ\n\ +9PKKlb8mmr3BB9A45ZNwLT6G9AK3+qkZLHojeSA+m84/a6GP4svAgMBAAE=\n\ -----END RSA PUBLIC KEY-----\ "; const char *PublicBetaKey = "\ -----BEGIN RSA PUBLIC KEY-----\n\ MIGJAoGBALWu9GGs0HED7KG7BM73CFZ6o0xufKBRQsdnq3lwA8nFQEvmdu+g/I1j\n\ 0LQ+0IQO7GW4jAgzF/4+soPDb6uHQeNFrlVx1JS9DZGhhjZ5rf65yg11nTCIHZCG\n\ w/CVnbwQOw0g5GBwwFV3r0uTTvy44xx8XXxk+Qknu4eBCsmrAFNnAgMBAAE=\n\ -----END RSA PUBLIC KEY-----\ "; extern const char *PrivateKey; extern const char *PrivateBetaKey; #include "../../../../DesktopPrivate/packer_private.h" // RSA PRIVATE KEYS for update signing #include "../../../../DesktopPrivate/alpha_private.h" // private key for alpha version file generation QString countAlphaVersionSignature(quint64 version); // sha1 hash typedef unsigned char uchar; typedef unsigned int uint32; typedef signed int int32; namespace{ struct BIODeleter { void operator()(BIO *value) { BIO_free(value); } }; inline auto makeBIO(const void *buf, int len) { return std::unique_ptr{ BIO_new_mem_buf(buf, len), }; } inline uint32 sha1Shift(uint32 v, uint32 shift) { return ((v << shift) | (v >> (32 - shift))); } void sha1PartHash(uint32 *sha, uint32 *temp) { uint32 a = sha[0], b = sha[1], c = sha[2], d = sha[3], e = sha[4], round = 0; #define _shiftswap(f, v) { \ uint32 t = sha1Shift(a, 5) + (f) + e + v + temp[round]; \ e = d; \ d = c; \ c = sha1Shift(b, 30); \ b = a; \ a = t; \ ++round; \ } #define _shiftshiftswap(f, v) { \ temp[round] = sha1Shift((temp[round - 3] ^ temp[round - 8] ^ temp[round - 14] ^ temp[round - 16]), 1); \ _shiftswap(f, v) \ } while (round < 16) _shiftswap((b & c) | (~b & d), 0x5a827999) while (round < 20) _shiftshiftswap((b & c) | (~b & d), 0x5a827999) while (round < 40) _shiftshiftswap(b ^ c ^ d, 0x6ed9eba1) while (round < 60) _shiftshiftswap((b & c) | (b & d) | (c & d), 0x8f1bbcdc) while (round < 80) _shiftshiftswap(b ^ c ^ d, 0xca62c1d6) #undef _shiftshiftswap #undef _shiftswap sha[0] += a; sha[1] += b; sha[2] += c; sha[3] += d; sha[4] += e; } } // namespace int32 *hashSha1(const void *data, uint32 len, void *dest) { const uchar *buf = (const uchar *)data; uint32 temp[80], block = 0, end; uint32 sha[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; for (end = block + 64; block + 64 <= len; end = block + 64) { for (uint32 i = 0; block < end; block += 4) { temp[i++] = (uint32) buf[block + 3] | (((uint32) buf[block + 2]) << 8) | (((uint32) buf[block + 1]) << 16) | (((uint32) buf[block]) << 24); } sha1PartHash(sha, temp); } end = len - block; memset(temp, 0, sizeof(uint32) * 16); uint32 last = 0; for (; last < end; ++last) { temp[last >> 2] |= (uint32)buf[last + block] << ((3 - (last & 0x03)) << 3); } temp[last >> 2] |= 0x80 << ((3 - (last & 3)) << 3); if (end >= 56) { sha1PartHash(sha, temp); memset(temp, 0, sizeof(uint32) * 16); } temp[15] = len << 3; sha1PartHash(sha, temp); uchar *sha1To = (uchar*)dest; for (int32 i = 19; i >= 0; --i) { sha1To[i] = (sha[i >> 2] >> (((3 - i) & 0x03) << 3)) & 0xFF; } return (int32*)sha1To; } QString AlphaSignature; int writeAlphaKey() { if (!AlphaVersion) { return 0; } QString keyName(QString("talpha_%1_key").arg(AlphaVersion)); QFile key(keyName); if (!key.open(QIODevice::WriteOnly)) { cout << "Can't open '" << keyName.toUtf8().constData() << "' for write..\n"; return -1; } key.write(AlphaSignature.toUtf8()); key.close(); return 0; } int main(int argc, char *argv[]) { QString workDir; QString remove; int version = 0; [[maybe_unused]] bool targetwin64 = false; [[maybe_unused]] bool targetwinarm = false; [[maybe_unused]] bool targetarmac = false; QFileInfoList files; for (int i = 0; i < argc; ++i) { if (string("-path") == argv[i] && i + 1 < argc) { QString path = workDir + QString(argv[i + 1]); QFileInfo info(path); files.push_back(info); if (remove.isEmpty()) remove = info.canonicalPath() + "/"; } else if (string("-target") == argv[i] && i + 1 < argc) { targetwin64 = (string("win64") == argv[i + 1]); targetwinarm = (string("winarm") == argv[i + 1]); } else if (string("-arch") == argv[i] && i + 1 < argc) { targetarmac = (string("arm64") == argv[i + 1]); if (!targetarmac && string("x86_64") != argv[i + 1]) { cout << "Bad -arch param value passed: " << argv[i + 1] << "\n"; return -1; } } else if (string("-version") == argv[i] && i + 1 < argc) { version = QString(argv[i + 1]).toInt(); } else if (string("-beta") == argv[i]) { BetaChannel = true; } else if (string("-alphakey") == argv[i]) { OnlyAlphaKey = true; } else if (string("-alpha") == argv[i] && i + 1 < argc) { AlphaVersion = QString(argv[i + 1]).toULongLong(); if (AlphaVersion > version * 1000ULL && AlphaVersion < (version + 1) * 1000ULL) { BetaChannel = false; AlphaSignature = countAlphaVersionSignature(AlphaVersion); if (AlphaSignature.isEmpty()) { return -1; } } else { cout << "Bad -alpha param value passed, should be for the same version: " << version << ", alpha: " << AlphaVersion << "\n"; return -1; } } } if (OnlyAlphaKey) { return writeAlphaKey(); } if (files.isEmpty() || remove.isEmpty() || version <= 1016 || version > 999999999) { #ifdef Q_OS_WIN cout << "Usage: Packer.exe -path {file} -version {version} OR Packer.exe -path {dir} -version {version}\n"; #elif defined Q_OS_MAC cout << "Usage: Packer.app -path {file} -version {version} OR Packer.app -path {dir} -version {version}\n"; #else cout << "Usage: Packer -path {file} -version {version} OR Packer -path {dir} -version {version}\n"; #endif return -1; } bool hasDirs = true; while (hasDirs) { hasDirs = false; for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { QFileInfo info(*i); QString fullPath = info.canonicalFilePath(); if (info.isDir()) { hasDirs = true; files.erase(i); QDir d = QDir(info.absoluteFilePath()); QString fullDir = d.canonicalPath(); QStringList entries = d.entryList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); files.append(d.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot)); break; } else if (!info.isReadable()) { cout << "Can't read: " << info.absoluteFilePath().toUtf8().constData() << "\n"; return -1; } else if (info.isHidden()) { hasDirs = true; files.erase(i); break; } } } for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { QFileInfo info(*i); if (!info.canonicalFilePath().startsWith(remove)) { cout << "Can't find '" << remove.toUtf8().constData() << "' in file '" << info.canonicalFilePath().toUtf8().constData() << "' :(\n"; return -1; } } QByteArray result; { QBuffer buffer(&result); buffer.open(QIODevice::WriteOnly); QDataStream stream(&buffer); stream.setVersion(QDataStream::Qt_5_1); if (AlphaVersion) { stream << quint32(0x7FFFFFFF); stream << quint64(AlphaVersion); } else { stream << quint32(version); } stream << quint32(files.size()); cout << "Found " << files.size() << " file" << (files.size() == 1 ? "" : "s") << "..\n"; for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { QFileInfo info(*i); QString fullName = info.canonicalFilePath(); QString name = fullName.mid(remove.length()); cout << name.toUtf8().constData() << " (" << info.size() << ")\n"; QFile f(fullName); if (!f.open(QIODevice::ReadOnly)) { cout << "Can't open '" << fullName.toUtf8().constData() << "' for read..\n"; return -1; } QByteArray inner = f.readAll(); stream << name << quint32(inner.size()) << inner; #ifndef Q_OS_WIN stream << (QFileInfo(fullName).isExecutable() ? true : false); #endif } if (stream.status() != QDataStream::Ok) { cout << "Stream status is bad: " << stream.status() << "\n"; return -1; } } int32 resultSize = result.size(); cout << "Compression start, size: " << resultSize << "\n"; QByteArray compressed, resultCheck; #if defined Q_OS_WIN && !defined PACKER_USE_PACKAGED // use Lzma SDK for win const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size size_t compressedLen = compressed.size() - hSize; size_t outPropsSize = LZMA_PROPS_SIZE; uchar *_dest = (uchar*)(compressed.data() + hSize); size_t *_destLen = &compressedLen; const uchar *_src = (const uchar*)(result.constData()); size_t _srcLen = result.size(); uchar *_outProps = (uchar*)(compressed.data() + hSigLen + hShaLen); int res = LzmaCompress(_dest, _destLen, _src, _srcLen, _outProps, &outPropsSize, 9, 64 * 1024 * 1024, 4, 0, 2, 273, 2); if (res != SZ_OK) { cout << "Error in compression: " << res << "\n"; return -1; } compressed.resize(int(hSize + compressedLen)); memcpy(compressed.data() + hSigLen + hShaLen + hPropsLen, &resultSize, hOriginalSizeLen); cout << "Compressed to size: " << compressedLen << "\n"; cout << "Checking uncompressed..\n"; int32 resultCheckLen; memcpy(&resultCheckLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); if (resultCheckLen <= 0 || resultCheckLen > 1024 * 1024 * 1024) { cout << "Bad result len: " << resultCheckLen << "\n"; return -1; } resultCheck.resize(resultCheckLen); size_t resultLen = resultCheck.size(); SizeT srcLen = compressedLen; int uncompressRes = LzmaUncompress((uchar*)resultCheck.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); if (uncompressRes != SZ_OK) { cout << "Uncompress failed: " << uncompressRes << "\n"; return -1; } if (resultLen != size_t(result.size())) { cout << "Uncompress bad size: " << resultLen << ", was: " << result.size() << "\n"; return -1; } #else // use liblzma for others const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size size_t compressedLen = compressed.size() - hSize; lzma_stream stream = LZMA_STREAM_INIT; int preset = 9 | LZMA_PRESET_EXTREME; lzma_ret ret = lzma_easy_encoder(&stream, preset, LZMA_CHECK_CRC64); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error initializing the encoder: " << msg << " (error code " << ret << ")\n"; return -1; } stream.avail_in = resultSize; stream.next_in = (uint8_t*)result.constData(); stream.avail_out = compressedLen; stream.next_out = (uint8_t*)(compressed.data() + hSize); lzma_ret res = lzma_code(&stream, LZMA_FINISH); compressedLen -= stream.avail_out; lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_DATA_ERROR: msg = "File size limits exceeded"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error in compression: " << msg << " (error code " << res << ")\n"; return -1; } compressed.resize(int(hSize + compressedLen)); memcpy(compressed.data() + hSigLen + hShaLen, &resultSize, hOriginalSizeLen); cout << "Compressed to size: " << compressedLen << "\n"; cout << "Checking uncompressed..\n"; int32 resultCheckLen; memcpy(&resultCheckLen, compressed.constData() + hSigLen + hShaLen, hOriginalSizeLen); if (resultCheckLen <= 0 || resultCheckLen > 1024 * 1024 * 1024) { cout << "Bad result len: " << resultCheckLen << "\n"; return -1; } resultCheck.resize(resultCheckLen); size_t resultLen = resultCheck.size(); stream = LZMA_STREAM_INIT; ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error initializing the decoder: " << msg << " (error code " << ret << ")\n"; return -1; } stream.avail_in = compressedLen; stream.next_in = (uint8_t*)(compressed.constData() + hSize); stream.avail_out = resultLen; stream.next_out = (uint8_t*)resultCheck.data(); res = lzma_code(&stream, LZMA_FINISH); if (stream.avail_in) { cout << "Error in decompression, " << stream.avail_in << " bytes left in _in of " << compressedLen << " whole.\n"; return -1; } else if (stream.avail_out) { cout << "Error in decompression, " << stream.avail_out << " bytes free left in _out of " << resultLen << " whole.\n"; return -1; } lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break; case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break; case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error in decompression: " << msg << " (error code " << res << ")\n"; return -1; } #endif if (memcmp(result.constData(), resultCheck.constData(), resultLen)) { cout << "Data differ :(\n"; return -1; } /**/ result = resultCheck = QByteArray(); cout << "Counting SHA1 hash..\n"; uchar sha1Buffer[20]; memcpy(compressed.data() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, uint32(compressedLen + hPropsLen + hOriginalSizeLen), sha1Buffer), hShaLen); // count sha1 uint32 siglen = 0; cout << "Signing..\n"; RSA *prKey = [] { const auto bio = makeBIO( const_cast( (BetaChannel || AlphaVersion) ? PrivateBetaKey : PrivateKey), -1); return PEM_read_bio_RSAPrivateKey(bio.get(), 0, 0, 0); }(); if (!prKey) { cout << "Could not read RSA private key!\n"; return -1; } if (RSA_size(prKey) != hSigLen) { cout << "Bad private key, size: " << RSA_size(prKey) << "\n"; RSA_free(prKey); return -1; } if (RSA_sign(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (uchar*)(compressed.data()), &siglen, prKey) != 1) { // count signature cout << "Signing failed!\n"; RSA_free(prKey); return -1; } RSA_free(prKey); if (siglen != hSigLen) { cout << "Bad signature length: " << siglen << "\n"; return -1; } /* cout << "Checking signature..\n"; RSA *pbKey = [] { const auto bio = makeBIO( const_cast( (BetaChannel || AlphaVersion) ? PublicBetaKey : PublicKey), -1); return PEM_read_bio_RSAPublicKey(bio.get(), 0, 0, 0); }(); if (!pbKey) { cout << "Could not read RSA public key!\n"; return -1; } if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), siglen, pbKey) != 1) { // verify signature RSA_free(pbKey); cout << "Signature verification failed!\n"; return -1; } cout << "Signature verified!\n"; RSA_free(pbKey); */ #ifdef Q_OS_WIN QString outName((targetwinarm ? QString("tarm64upd%1") : targetwin64 ? QString("tx64upd%1") : QString("tupdate%1")).arg(AlphaVersion ? AlphaVersion : version)); #elif defined Q_OS_MAC QString outName((targetarmac ? QString("tarmacupd%1") : QString("tmacupd%1")).arg(AlphaVersion ? AlphaVersion : version)); #else QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version)); #endif if (AlphaVersion) { outName += "_" + AlphaSignature; } QFile out(outName); if (!out.open(QIODevice::WriteOnly)) { cout << "Can't open '" << outName.toUtf8().constData() << "' for write..\n"; return -1; } out.write(compressed); out.close(); cout << "Update file '" << outName.toUtf8().constData() << "' written successfully!\n"; return writeAlphaKey(); } QString countAlphaVersionSignature(quint64 version) { // duplicated in autoupdater.cpp /* QByteArray cAlphaPrivateKey(AlphaPrivateKey); if (cAlphaPrivateKey.isEmpty()) { cout << "Error: Trying to count alpha version signature without alpha private key!\n"; return QString(); } QByteArray signedData = (QLatin1String("TelegramBeta_") + QString::number(version, 16).toLower()).toUtf8(); static const int32 shaSize = 20, keySize = 128; uchar sha1Buffer[shaSize]; hashSha1(signedData.constData(), signedData.size(), sha1Buffer); // count sha1 uint32 siglen = 0; RSA *prKey = [&] { const auto bio = makeBIO( const_cast(cAlphaPrivateKey.constData()), -1); return PEM_read_bio_RSAPrivateKey(bio.get(), 0, 0, 0); }(); if (!prKey) { cout << "Error: Could not read alpha private key!\n"; return QString(); } if (RSA_size(prKey) != keySize) { cout << "Error: Bad alpha private key size: " << RSA_size(prKey) << "\n"; RSA_free(prKey); return QString(); } QByteArray signature; signature.resize(keySize); if (RSA_sign(NID_sha1, (const uchar*)(sha1Buffer), shaSize, (uchar*)(signature.data()), &siglen, prKey) != 1) { // count signature cout << "Error: Counting alpha version signature failed!\n"; RSA_free(prKey); return QString(); } RSA_free(prKey); if (siglen != keySize) { cout << "Error: Bad alpha version signature length: " << siglen << "\n"; return QString(); } signature = signature.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); signature = signature.replace('-', '8').replace('_', 'B'); return QString::fromUtf8(signature.mid(19, 32)); */ return "0"; } ================================================ FILE: Telegram/SourceFiles/_other/packer.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include #include #include #include #include #include #include #include extern "C" { #include #include #include #include #include #include #include } // extern "C" #if defined Q_OS_WIN && !defined PACKER_USE_PACKAGED // use Lzma SDK for win #include #else #include #endif #include #include #include using std::string; using std::wstring; using std::cout; ================================================ FILE: Telegram/SourceFiles/_other/startup_task_win.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include #include #include #include using namespace std; constexpr auto kMaxPathLong = 32767; [[nodiscard]] std::wstring ExecutableDirectory() { auto exePath = std::array{ 0 }; const auto exeLength = GetModuleFileName( nullptr, exePath.data(), kMaxPathLong + 1); if (!exeLength || exeLength >= kMaxPathLong + 1) { return {}; } const auto exe = std::wstring(exePath.data()); const auto last1 = exe.find_last_of('\\'); const auto last2 = exe.find_last_of('/'); const auto last = std::max( (last1 == std::wstring::npos) ? -1 : int(last1), (last2 == std::wstring::npos) ? -1 : int(last2)); if (last < 0) { return {}; } return exe.substr(0, last); } int APIENTRY wWinMain( HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdParamarg, int cmdShow) { const auto directory = ExecutableDirectory(); if (!directory.empty()) { ShellExecute( nullptr, nullptr, (directory + L"\\Telegram.exe").c_str(), L"-autostart", directory.data(), SW_SHOWNORMAL); } return 0; } ================================================ FILE: Telegram/SourceFiles/_other/updater.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include #include #ifdef small #undef small #endif // small #pragma warning(push) #pragma warning(disable:4091) #include #include #pragma warning(pop) #include #include #include #include using std::deque; using std::wstring; extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter; LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); static int updaterVersion = 1000; static const WCHAR *updaterVersionStr = L"0.1.0"; ================================================ FILE: Telegram/SourceFiles/_other/updater_linux.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #define _GLIBCXX_USE_CXX11_ABI 0 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using std::string; using std::deque; using std::vector; using std::cout; bool do_mkdir(const char *path) { // from http://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux struct stat statbuf; if (stat(path, &statbuf) != 0) { /* Directory does not exist. EEXIST for race condition */ if (mkdir(path, S_IRWXU) != 0 && errno != EEXIST) return false; } else if (!S_ISDIR(statbuf.st_mode)) { errno = ENOTDIR; return false; } return true; } bool _debug = false; bool writeprotected = false; string updaterDir; string updaterName; string workDir; string exeName; string exePath; string argv0; FILE *_logFile = 0; void openLog() { if (!_debug || _logFile) return; if (!do_mkdir((workDir + "DebugLogs").c_str())) { return; } time_t timer; time(&timer); struct tm *t = localtime(&timer); static const int maxFileLen = 65536; char logName[maxFileLen]; sprintf(logName, "%sDebugLogs/%04d%02d%02d_%02d%02d%02d_upd.txt", workDir.c_str(), t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); _logFile = fopen(logName, "w"); } void closeLog() { if (!_logFile) return; fclose(_logFile); _logFile = 0; } void writeLog(const char *format, ...) { if (!_logFile) { return; } va_list args; va_start(args, format); vfprintf(_logFile, format, args); fprintf(_logFile, "\n"); fflush(_logFile); va_end(args); } bool copyFile(const char *from, const char *to) { FILE *ffrom = fopen(from, "rb"), *fto = fopen(to, "wb"); if (!ffrom) { if (fto) fclose(fto); return false; } if (!fto) { fclose(ffrom); return false; } static const int BufSize = 65536; char buf[BufSize]; while (size_t size = fread(buf, 1, BufSize, ffrom)) { fwrite(buf, 1, size, fto); } struct stat fst; // from http://stackoverflow.com/questions/5486774/keeping-fileowner-and-permissions-after-copying-file-in-c //let's say this wont fail since you already worked OK on that fp if (fstat(fileno(ffrom), &fst) != 0) { fclose(ffrom); fclose(fto); return false; } //update to the same uid/gid if (!writeprotected && fchown(fileno(fto), fst.st_uid, fst.st_gid) != 0) { fclose(ffrom); fclose(fto); return false; } //update the permissions if (fchmod(fileno(fto), fst.st_mode) != 0) { fclose(ffrom); fclose(fto); return false; } fclose(ffrom); fclose(fto); return true; } bool remove_directory(const string &path) { // from http://stackoverflow.com/questions/2256945/removing-a-non-empty-directory-programmatically-in-c-or-c DIR *d = opendir(path.c_str()); writeLog("Removing dir '%s'", path.c_str()); if (!d) { writeLog("Could not open dir '%s'", path.c_str()); return (errno == ENOENT); } while (struct dirent *p = readdir(d)) { /* Skip the names "." and ".." as we don't want to recurse on them. */ if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) continue; string fname = path + '/' + p->d_name; struct stat statbuf; writeLog("Trying to get stat() for '%s'", fname.c_str()); if (!stat(fname.c_str(), &statbuf)) { if (S_ISDIR(statbuf.st_mode)) { if (!remove_directory(fname.c_str())) { closedir(d); return false; } } else { writeLog("Unlinking file '%s'", fname.c_str()); if (unlink(fname.c_str())) { writeLog("Failed to unlink '%s'", fname.c_str()); closedir(d); return false; } } } else { writeLog("Failed to call stat() on '%s'", fname.c_str()); } } closedir(d); writeLog("Finally removing dir '%s'", path.c_str()); return !rmdir(path.c_str()); } bool mkpath(const char *path) { int status = 0, pathsize = strlen(path) + 1; char *copypath = new char[pathsize]; memcpy(copypath, path, pathsize); char *pp = copypath, *sp; while (status == 0 && (sp = strchr(pp, '/')) != 0) { if (sp != pp) { /* Neither root nor double slash in path */ *sp = '\0'; if (!do_mkdir(copypath)) { delete[] copypath; return false; } *sp = '/'; } pp = sp + 1; } delete[] copypath; return do_mkdir(path); } bool equal(string a, string b) { std::transform(a.begin(), a.end(), a.begin(), ::tolower); std::transform(b.begin(), b.end(), b.begin(), ::tolower); return a == b; } void delFolder() { string delPathOld = workDir + "tupdates/ready", delPath = workDir + "tupdates/temp", delFolder = workDir + "tupdates"; writeLog("Fully clearing old path '%s'..", delPathOld.c_str()); if (!remove_directory(delPathOld)) { writeLog("Failed to clear old path! :( New path was used?.."); } writeLog("Fully clearing path '%s'..", delPath.c_str()); if (!remove_directory(delPath)) { writeLog("Error: failed to clear path! :("); } rmdir(delFolder.c_str()); } bool update() { writeLog("Update started.."); string updDir = workDir + "tupdates/temp", readyFilePath = workDir + "tupdates/temp/ready", tdataDir = workDir + "tupdates/temp/tdata"; { FILE *readyFile = fopen(readyFilePath.c_str(), "rb"); if (readyFile) { fclose(readyFile); writeLog("Ready file found! Using new path '%s'..", updDir.c_str()); } else { updDir = workDir + "tupdates/ready"; // old tdataDir = workDir + "tupdates/ready/tdata"; writeLog("Ready file not found! Using old path '%s'..", updDir.c_str()); } } deque dirs; dirs.push_back(updDir); deque from, to, forcedirs; do { string dir = dirs.front(); dirs.pop_front(); string toDir = exePath; if (dir.size() > updDir.size() + 1) { toDir += (dir.substr(updDir.size() + 1) + '/'); forcedirs.push_back(toDir); writeLog("Parsing dir '%s' in update tree..", toDir.c_str()); } DIR *d = opendir(dir.c_str()); if (!d) { writeLog("Failed to open dir %s", dir.c_str()); return false; } while (struct dirent *p = readdir(d)) { /* Skip the names "." and ".." as we don't want to recurse on them. */ if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) continue; string fname = dir + '/' + p->d_name; struct stat statbuf; if (fname.substr(0, tdataDir.size()) == tdataDir && (fname.size() <= tdataDir.size() || fname.at(tdataDir.size()) == '/')) { writeLog("Skipping 'tdata' path '%s'", fname.c_str()); } else if (!stat(fname.c_str(), &statbuf)) { if (S_ISDIR(statbuf.st_mode)) { dirs.push_back(fname); writeLog("Added dir '%s' in update tree..", fname.c_str()); } else { string tofname = exePath + fname.substr(updDir.size() + 1); if (equal(tofname, updaterName)) { // bad update - has Updater - delete all dir writeLog("Error: bad update, has Updater! '%s' equal '%s'", tofname.c_str(), updaterName.c_str()); delFolder(); return false; } else if (equal(tofname, exePath + "Forkgram") && exeName != "Forkgram") { string fullBinaryPath = exePath + exeName; writeLog("Target binary found: '%s', changing to '%s'", tofname.c_str(), fullBinaryPath.c_str()); tofname = fullBinaryPath; } if (fname == readyFilePath) { writeLog("Skipped ready file '%s'", fname.c_str()); } else { from.push_back(fname); to.push_back(tofname); writeLog("Added file '%s' to be copied to '%s'", fname.c_str(), tofname.c_str()); } } } else { writeLog("Could not get stat() for file %s", fname.c_str()); } } closedir(d); } while (!dirs.empty()); for (size_t i = 0; i < forcedirs.size(); ++i) { string forcedir = forcedirs[i]; writeLog("Forcing dir '%s'..", forcedir.c_str()); if (!forcedir.empty() && !mkpath(forcedir.c_str())) { writeLog("Error: failed to create dir '%s'..", forcedir.c_str()); delFolder(); return false; } } for (size_t i = 0; i < from.size(); ++i) { string fname = from[i], tofname = to[i]; // it is necessary to remove the old file to not to get an error if appimage file is used by fuse struct stat statbuf; writeLog("Trying to get stat() for '%s'", tofname.c_str()); if (!stat(tofname.c_str(), &statbuf)) { if (S_ISDIR(statbuf.st_mode)) { writeLog("Fully clearing path '%s'..", tofname.c_str()); if (!remove_directory(tofname.c_str())) { writeLog("Error: failed to clear path '%s'", tofname.c_str()); delFolder(); return false; } } else { writeLog("Unlinking file '%s'", tofname.c_str()); if (unlink(tofname.c_str())) { writeLog("Error: failed to unlink '%s'", tofname.c_str()); delFolder(); return false; } } } writeLog("Copying file '%s' to '%s'..", fname.c_str(), tofname.c_str()); int copyTries = 0, triesLimit = 30; do { if (!copyFile(fname.c_str(), tofname.c_str())) { ++copyTries; usleep(100000); } else { break; } } while (copyTries < triesLimit); if (copyTries == triesLimit) { writeLog("Error: failed to copy, asking to retry.."); delFolder(); return false; } } writeLog("Update succeed! Clearing folder.."); delFolder(); return true; } string CurrentExecutablePath(int argc, char *argv[]) { constexpr auto kMaxPath = 1024; char result[kMaxPath] = { 0 }; auto count = readlink("/proc/self/exe", result, kMaxPath); if (count > 0) { return string(result); } // Fallback to the first command line argument. return argc ? string(argv[0]) : string(); } int main(int argc, char *argv[]) { bool needupdate = true; bool autostart = false; bool debug = false; bool tosettings = false; bool startintray = false; bool customWorkingDir = false; bool justUpdate = false; char *key = 0; char *workdir = 0; for (int i = 1; i < argc; ++i) { if (equal(argv[i], "-noupdate")) { needupdate = false; } else if (equal(argv[i], "-autostart")) { autostart = true; } else if (equal(argv[i], "-debug")) { debug = _debug = true; } else if (equal(argv[i], "-startintray")) { startintray = true; } else if (equal(argv[i], "-tosettings")) { tosettings = true; } else if (equal(argv[i], "-workdir_custom")) { customWorkingDir = true; } else if (equal(argv[i], "-writeprotected")) { writeprotected = true; justUpdate = true; } else if (equal(argv[i], "-justupdate")) { justUpdate = true; } else if (equal(argv[i], "-key") && ++i < argc) { key = argv[i]; } else if (equal(argv[i], "-workpath") && ++i < argc) { workDir = workdir = argv[i]; } else if (equal(argv[i], "-exename") && ++i < argc) { exeName = argv[i]; } else if (equal(argv[i], "-exepath") && ++i < argc) { exePath = argv[i]; } else if (equal(argv[i], "-argv0") && ++i < argc) { argv0 = argv[i]; } } if (exeName.empty() || exeName.find('/') != string::npos) { exeName = "Forkgram"; } openLog(); writeLog("Updater started, new argments formatting.."); for (int i = 0; i < argc; ++i) { writeLog("Argument: '%s'", argv[i]); } if (needupdate) writeLog("Need to update!"); if (autostart) writeLog("From autostart!"); if (writeprotected) writeLog("Write Protected folder!"); updaterName = CurrentExecutablePath(argc, argv); writeLog("Updater binary full path is: %s", updaterName.c_str()); if (exePath.empty()) { writeLog("Executable path is not specified :("); } else { writeLog("Executable path: %s", exePath.c_str()); } if (updaterName.size() >= 7) { if (equal(updaterName.substr(updaterName.size() - 7), "Updater")) { updaterDir = updaterName.substr(0, updaterName.size() - 7); writeLog("Updater binary dir is: %s", updaterDir.c_str()); if (exePath.empty()) { exePath = updaterDir; writeLog("Using updater binary dir.", exePath.c_str()); } if (needupdate) { if (workDir.empty()) { // old app launched, update prepared in tupdates/ready (not in tupdates/temp) customWorkingDir = false; writeLog("No workdir, trying to figure it out"); struct passwd *pw = getpwuid(getuid()); if (pw && pw->pw_dir && strlen(pw->pw_dir)) { string tryDir = pw->pw_dir + string("/.TelegramDesktop/"); struct stat statbuf; writeLog("Trying to use '%s' as workDir, getting stat() for tupdates/ready", tryDir.c_str()); if (!stat((tryDir + "tupdates/ready").c_str(), &statbuf)) { writeLog("Stat got"); if (S_ISDIR(statbuf.st_mode)) { writeLog("It is directory, using home work dir"); workDir = tryDir; } } } if (workDir.empty()) { workDir = exePath; struct stat statbuf; writeLog("Trying to use current as workDir, getting stat() for tupdates/ready"); if (!stat("tupdates/ready", &statbuf)) { writeLog("Stat got"); if (S_ISDIR(statbuf.st_mode)) { writeLog("It is directory, using current dir"); workDir = string(); } } } } else { writeLog("Passed workpath is '%s'", workDir.c_str()); } update(); } } else { writeLog("Error: bad exe name!"); } } else { writeLog("Error: short exe name!"); } // let the parent launch instead if (justUpdate) { writeLog("Closing log and quitting.."); } else { const auto fullBinaryPath = exePath + exeName; auto values = vector(); const auto push = [&](string arg) { // Force null-terminated .data() call result. values.push_back(arg + char(0)); }; push(!argv0.empty() ? argv0 : fullBinaryPath); push("-noupdate"); if (autostart) push("-autostart"); if (debug) push("-debug"); if (startintray) push("-startintray"); if (tosettings) push("-tosettings"); if (key) { push("-key"); push(key); } if (customWorkingDir && workdir) { push("-workdir"); push(workdir); } auto args = vector(); for (auto &arg : values) { args.push_back(arg.data()); } args.push_back(nullptr); pid_t pid = fork(); switch (pid) { case -1: writeLog("fork() failed!"); return 1; case 0: execv(fullBinaryPath.c_str(), args.data()); return 1; } writeLog("Executed Forkgram, closing log and quitting.."); } closeLog(); return 0; } ================================================ FILE: Telegram/SourceFiles/_other/updater_osx.m ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #import #include NSString *appName = @"Telegram.app"; NSString *appDir = nil; NSString *workDir = nil; #ifdef _DEBUG BOOL _debug = YES; #else BOOL _debug = NO; #endif NSFileHandle *_logFile = nil; void openLog() { if (!_debug || _logFile) return; NSString *logDir = [workDir stringByAppendingString:@"DebugLogs"]; if (![[NSFileManager defaultManager] createDirectoryAtPath:logDir withIntermediateDirectories:YES attributes:nil error:nil]) { return; } NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; [fmt setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]]; [fmt setDateFormat:@"'DebugLogs/'yyyyMMdd'_'HHmmss'_update.txt'"]; NSString *logPath = [workDir stringByAppendingString:[fmt stringFromDate:[NSDate date]]]; [[NSFileManager defaultManager] createFileAtPath:logPath contents:nil attributes:nil]; _logFile = [NSFileHandle fileHandleForWritingAtPath:logPath]; } void closeLog() { if (!_logFile) return; [_logFile closeFile]; } void writeLog(NSString *msg) { if (!_logFile) return; [_logFile writeData:[[msg stringByAppendingString:@"\n"] dataUsingEncoding:NSUTF8StringEncoding]]; [_logFile synchronizeFile]; } void RemoveQuarantineAttribute(NSString *path) { const char *kQuarantineAttribute = "com.apple.quarantine"; writeLog([@"Removing quarantine: " stringByAppendingString:path]); removexattr([path fileSystemRepresentation], kQuarantineAttribute, 0); } void RemoveQuarantineFromBundle(NSString *path) { RemoveQuarantineAttribute(path); RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/MacOS/Telegram"]); RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/Helpers/crashpad_handler"]); RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/Frameworks/Updater"]); } void delFolder() { writeLog([@"Fully clearing old path: " stringByAppendingString:[workDir stringByAppendingString:@"tupdates/ready"]]); if (![[NSFileManager defaultManager] removeItemAtPath:[workDir stringByAppendingString:@"tupdates/ready"] error:nil]) { writeLog(@"Failed to clear old path! :( New path was used?.."); } writeLog([@"Fully clearing new path: " stringByAppendingString:[workDir stringByAppendingString:@"tupdates/temp"]]); if (![[NSFileManager defaultManager] removeItemAtPath:[workDir stringByAppendingString:@"tupdates/temp"] error:nil]) { writeLog(@"Error: failed to clear new path! :("); } rmdir([[workDir stringByAppendingString:@"tupdates"] fileSystemRepresentation]); } int main(int argc, const char * argv[]) { NSString *path = [[NSBundle mainBundle] bundlePath]; if (!path) { return -1; } NSRange range = [path rangeOfString:@".app/" options:NSBackwardsSearch]; if (range.location == NSNotFound) { return -1; } path = [path substringToIndex:range.location > 0 ? range.location : 0]; range = [path rangeOfString:@"/" options:NSBackwardsSearch]; NSString *appRealName = (range.location == NSNotFound) ? path : [path substringFromIndex:range.location + 1]; appRealName = [[NSArray arrayWithObjects:appRealName, @".app", nil] componentsJoinedByString:@""]; appDir = (range.location == NSNotFound) ? @"" : [path substringToIndex:range.location + 1]; NSString *appDirFull = [appDir stringByAppendingString:appRealName]; openLog(); pid_t procId = 0; BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO; BOOL customWorkingDir = NO; NSString *key = nil; for (int i = 0; i < argc; ++i) { if ([@"-workpath" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { if (++i < argc) { workDir = [NSString stringWithUTF8String:argv[i]]; } } else if ([@"-procid" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { if (++i < argc) { NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; procId = [[formatter numberFromString:[NSString stringWithUTF8String:argv[i]]] intValue]; } } else if ([@"-noupdate" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { update = NO; } else if ([@"-tosettings" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { toSettings = YES; } else if ([@"-autostart" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { autoStart = YES; } else if ([@"-debug" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { _debug = YES; } else if ([@"-startintray" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { startInTray = YES; } else if ([@"-workdir_custom" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { customWorkingDir = YES; } else if ([@"-key" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { if (++i < argc) key = [NSString stringWithUTF8String:argv[i]]; } } if (!workDir) { workDir = appDir; customWorkingDir = NO; } openLog(); NSMutableArray *argsArr = [[NSMutableArray alloc] initWithCapacity:argc]; for (int i = 0; i < argc; ++i) { [argsArr addObject:[NSString stringWithUTF8String:argv[i]]]; } writeLog([[NSArray arrayWithObjects:@"Arguments: '", [argsArr componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]); if (key) writeLog([@"Key: " stringByAppendingString:key]); if (toSettings) writeLog(@"To Settings!"); if (procId) { NSRunningApplication *app = [NSRunningApplication runningApplicationWithProcessIdentifier:procId]; for (int i = 0; i < 5 && app != nil && ![app isTerminated]; ++i) { usleep(200000); app = [NSRunningApplication runningApplicationWithProcessIdentifier:procId]; } if (app) [app forceTerminate]; app = [NSRunningApplication runningApplicationWithProcessIdentifier:procId]; for (int i = 0; i < 5 && app != nil && ![app isTerminated]; ++i) { usleep(200000); app = [NSRunningApplication runningApplicationWithProcessIdentifier:procId]; } } if (update) { NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *readyFilePath = [workDir stringByAppendingString:@"tupdates/temp/ready"]; NSString *srcDir = [workDir stringByAppendingString:@"tupdates/temp/"], *srcEnum = [workDir stringByAppendingString:@"tupdates/temp"]; if ([fileManager fileExistsAtPath:readyFilePath]) { writeLog([@"Ready file found! Using new path: " stringByAppendingString: srcEnum]); } else { srcDir = [workDir stringByAppendingString:@"tupdates/ready/"]; // old srcEnum = [workDir stringByAppendingString:@"tupdates/ready"]; writeLog([@"Ready file not found! Using old path: " stringByAppendingString: srcEnum]); } writeLog([@"Starting update files iteration, path: " stringByAppendingString: srcEnum]); // Take the Updater (this currently running binary) from the place where it was placed by Telegram // and copy it to the folder with the new version of the app (ready), // so it won't be deleted when we will clear the "Telegram.app/Contents" folder. NSString *oldVersionUpdaterPath = [appDirFull stringByAppendingString: @"/Contents/Frameworks/Updater" ]; NSString *newVersionUpdaterPath = [srcEnum stringByAppendingString:[[NSArray arrayWithObjects:@"/", appName, @"/Contents/Frameworks/Updater", nil] componentsJoinedByString:@""]]; writeLog([[NSArray arrayWithObjects: @"Copying Updater from old path ", oldVersionUpdaterPath, @" to new path ", newVersionUpdaterPath, nil] componentsJoinedByString:@""]); if (![fileManager fileExistsAtPath:newVersionUpdaterPath]) { if (![fileManager copyItemAtPath:oldVersionUpdaterPath toPath:newVersionUpdaterPath error:nil]) { writeLog([[NSArray arrayWithObjects: @"Failed to copy file from ", oldVersionUpdaterPath, @" to ", newVersionUpdaterPath, nil] componentsJoinedByString:@""]); delFolder(); return -1; } } NSString *contentsPath = [appDirFull stringByAppendingString: @"/Contents"]; writeLog([[NSArray arrayWithObjects: @"Clearing dir ", contentsPath, nil] componentsJoinedByString:@""]); if (![fileManager removeItemAtPath:contentsPath error:nil]) { writeLog([@"Failed to clear path for directory " stringByAppendingString:contentsPath]); delFolder(); return -1; } NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey]; NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtURL:[NSURL fileURLWithPath:srcEnum] includingPropertiesForKeys:keys options:0 errorHandler:^(NSURL *url, NSError *error) { writeLog([[[@"Error in enumerating " stringByAppendingString:[url absoluteString]] stringByAppendingString: @" error is: "] stringByAppendingString: [error description]]); return NO; }]; for (NSURL *url in enumerator) { NSString *srcPath = [url path]; writeLog([@"Handling file " stringByAppendingString:srcPath]); NSRange r = [srcPath rangeOfString:srcDir]; if (r.location != 0) { writeLog([@"Bad file found, no base path " stringByAppendingString:srcPath]); delFolder(); break; } NSString *pathPart = [srcPath substringFromIndex:r.length]; r = [pathPart rangeOfString:appName]; if (r.location != 0) { writeLog([@"Skipping not app file " stringByAppendingString:srcPath]); continue; } NSString *dstPath = [appDirFull stringByAppendingString:[pathPart substringFromIndex:r.length]]; NSError *error; NSNumber *isDirectory = nil; if (![url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) { writeLog([@"Failed to get IsDirectory for file " stringByAppendingString:[url path]]); delFolder(); break; } if ([isDirectory boolValue]) { writeLog([[NSArray arrayWithObjects: @"Copying dir ", srcPath, @" to ", dstPath, nil] componentsJoinedByString:@""]); if (![fileManager createDirectoryAtPath:dstPath withIntermediateDirectories:YES attributes:nil error:nil]) { writeLog([@"Failed to force path for directory " stringByAppendingString:dstPath]); delFolder(); break; } } else if ([srcPath isEqualToString:readyFilePath]) { writeLog([[NSArray arrayWithObjects: @"Skipping ready file ", srcPath, nil] componentsJoinedByString:@""]); } else if ([fileManager fileExistsAtPath:dstPath]) { if (![[NSData dataWithContentsOfFile:srcPath] writeToFile:dstPath atomically:YES]) { writeLog([@"Failed to edit file " stringByAppendingString:dstPath]); delFolder(); break; } } else { if (![fileManager copyItemAtPath:srcPath toPath:dstPath error:nil]) { writeLog([@"Failed to copy file to " stringByAppendingString:dstPath]); delFolder(); break; } } } delFolder(); } NSString *appPath = [[NSArray arrayWithObjects:appDir, appRealName, nil] componentsJoinedByString:@""]; RemoveQuarantineFromBundle(appPath); NSMutableArray *args = [[NSMutableArray alloc] initWithObjects: @"-noupdate", nil]; if (toSettings) [args addObject:@"-tosettings"]; if (_debug) [args addObject:@"-debug"]; if (startInTray) [args addObject:@"-startintray"]; if (autoStart) [args addObject:@"-autostart"]; if (key) { [args addObject:@"-key"]; [args addObject:key]; } if (customWorkingDir) { [args addObject:@"-workdir"]; [args addObject:workDir]; } writeLog([[NSArray arrayWithObjects:@"Running application '", appPath, @"' with args '", [args componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]); for (int i = 0; i < 5; ++i) { NSError *error = nil; NSRunningApplication *result = [[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:appPath] options:NSWorkspaceLaunchDefault configuration:[NSDictionary dictionaryWithObject:args forKey:NSWorkspaceLaunchConfigurationArguments] error:&error]; if (result) { closeLog(); return 0; } writeLog([[NSString stringWithFormat:@"Could not run application, error %ld: ", (long)[error code]] stringByAppendingString: error ? [error localizedDescription] : @"(nil)"]); usleep(200000); } closeLog(); return -1; } ================================================ FILE: Telegram/SourceFiles/_other/updater_win.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "updater.h" #include "base/platform/win/base_windows_safe_library.h" bool _debug = false; wstring updaterName, updaterDir, updateTo, exeName, customWorkingDir, customKeyFile; bool equal(const wstring &a, const wstring &b) { return !_wcsicmp(a.c_str(), b.c_str()); } void updateError(const WCHAR *msg, DWORD errorCode) { WCHAR errMsg[2048]; LPWSTR errorTextFormatted = nullptr; auto formatFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS; FormatMessage( formatFlags, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&errorTextFormatted, 0, 0); auto errorText = errorTextFormatted ? errorTextFormatted : L"(Unknown error)"; wsprintf(errMsg, L"%s, error code: %d\nError message: %s", msg, errorCode, errorText); MessageBox(0, errMsg, L"Update error!", MB_ICONERROR); LocalFree(errorTextFormatted); } HANDLE _logFile = 0; void openLog() { if (!_debug || _logFile) return; wstring logPath = L"DebugLogs"; if (!CreateDirectory(logPath.c_str(), NULL)) { DWORD errorCode = GetLastError(); if (errorCode && errorCode != ERROR_ALREADY_EXISTS) { updateError(L"Failed to create log directory", errorCode); return; } } SYSTEMTIME stLocalTime; GetLocalTime(&stLocalTime); static const int maxFileLen = MAX_PATH * 10; WCHAR logName[maxFileLen]; wsprintf(logName, L"DebugLogs\\%04d%02d%02d_%02d%02d%02d_upd.txt", stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond); _logFile = CreateFile(logName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (_logFile == INVALID_HANDLE_VALUE) { // :( updateError(L"Failed to create log file", GetLastError()); _logFile = 0; return; } } void closeLog() { if (!_logFile) return; CloseHandle(_logFile); _logFile = 0; } void writeLog(const wstring &msg) { if (!_logFile) return; wstring full = msg + L'\n'; DWORD written = 0; BOOL result = WriteFile(_logFile, full.c_str(), full.size() * sizeof(wchar_t), &written, 0); if (!result) { updateError((L"Failed to write log entry '" + msg + L"'").c_str(), GetLastError()); closeLog(); return; } BOOL flushr = FlushFileBuffers(_logFile); if (!flushr) { updateError((L"Failed to flush log on entry '" + msg + L"'").c_str(), GetLastError()); closeLog(); return; } } void fullClearPath(const wstring &dir) { WCHAR path[4096]; memcpy(path, dir.c_str(), (dir.size() + 1) * sizeof(WCHAR)); path[dir.size() + 1] = 0; writeLog(L"Fully clearing path '" + dir + L"'.."); SHFILEOPSTRUCT file_op = { NULL, FO_DELETE, path, L"", FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT, false, 0, L"" }; int res = SHFileOperation(&file_op); if (res) writeLog(L"Error: failed to clear path! :("); } void delFolder() { wstring delPathOld = L"tupdates\\ready", delPath = L"tupdates\\temp", delFolder = L"tupdates"; fullClearPath(delPathOld); fullClearPath(delPath); RemoveDirectory(delFolder.c_str()); } DWORD versionNum = 0, versionLen = 0, readLen = 0; WCHAR versionStr[32] = { 0 }; bool update() { writeLog(L"Update started.."); wstring updDir = L"tupdates\\temp", readyFilePath = L"tupdates\\temp\\ready", tdataDir = L"tupdates\\temp\\tdata"; { HANDLE readyFile = CreateFile(readyFilePath.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (readyFile != INVALID_HANDLE_VALUE) { CloseHandle(readyFile); } else { updDir = L"tupdates\\ready"; // old tdataDir = L"tupdates\\ready\\tdata"; } } HANDLE versionFile = CreateFile((tdataDir + L"\\version").c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (versionFile != INVALID_HANDLE_VALUE) { if (!ReadFile(versionFile, &versionNum, sizeof(DWORD), &readLen, NULL) || readLen != sizeof(DWORD)) { versionNum = 0; } else { if (versionNum == 0x7FFFFFFF) { // alpha version } else if (!ReadFile(versionFile, &versionLen, sizeof(DWORD), &readLen, NULL) || readLen != sizeof(DWORD) || versionLen > 63) { versionNum = 0; } else if (!ReadFile(versionFile, versionStr, versionLen, &readLen, NULL) || readLen != versionLen) { versionNum = 0; } } CloseHandle(versionFile); writeLog(L"Version file read."); } else { writeLog(L"Could not open version file to update registry :("); } deque dirs; dirs.push_back(updDir); deque from, to, forcedirs; do { wstring dir = dirs.front(); dirs.pop_front(); wstring toDir = updateTo; if (dir.size() > updDir.size() + 1) { toDir += (dir.substr(updDir.size() + 1) + L"\\"); forcedirs.push_back(toDir); writeLog(L"Parsing dir '" + toDir + L"' in update tree.."); } WIN32_FIND_DATA findData; HANDLE findHandle = FindFirstFileEx((dir + L"\\*").c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, 0, 0); if (findHandle == INVALID_HANDLE_VALUE) { DWORD errorCode = GetLastError(); if (errorCode == ERROR_PATH_NOT_FOUND) { // no update is ready return true; } writeLog(L"Error: failed to find update files :("); updateError(L"Failed to find update files", errorCode); delFolder(); return false; } do { wstring fname = dir + L"\\" + findData.cFileName; if (fname.substr(0, tdataDir.size()) == tdataDir && (fname.size() <= tdataDir.size() || fname.at(tdataDir.size()) == '/')) { writeLog(L"Skipped 'tdata' path '" + fname + L"'"); } else if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (findData.cFileName != wstring(L".") && findData.cFileName != wstring(L"..")) { dirs.push_back(fname); writeLog(L"Added dir '" + fname + L"' in update tree.."); } } else { wstring tofname = updateTo + fname.substr(updDir.size() + 1); if (equal(tofname, updaterName)) { // bad update - has Updater.exe - delete all dir writeLog(L"Error: bad update, has Updater.exe! '" + tofname + L"' equal '" + updaterName + L"'"); delFolder(); return false; } else if (equal(tofname, updateTo + L"Telegram.exe") && exeName != L"Telegram.exe") { wstring fullBinaryPath = updateTo + exeName; writeLog(L"Target binary found: '" + tofname + L"', changing to '" + fullBinaryPath + L"'"); tofname = fullBinaryPath; } if (equal(fname, readyFilePath)) { writeLog(L"Skipped ready file '" + fname + L"'"); } else { from.push_back(fname); to.push_back(tofname); writeLog(L"Added file '" + fname + L"' to be copied to '" + tofname + L"'"); } } } while (FindNextFile(findHandle, &findData)); DWORD errorCode = GetLastError(); if (errorCode && errorCode != ERROR_NO_MORE_FILES) { // everything is found writeLog(L"Error: failed to find next update file :("); updateError(L"Failed to find next update file", errorCode); delFolder(); return false; } FindClose(findHandle); } while (!dirs.empty()); for (size_t i = 0; i < forcedirs.size(); ++i) { wstring forcedir = forcedirs[i]; writeLog(L"Forcing dir '" + forcedir + L"'.."); if (!forcedir.empty() && !CreateDirectory(forcedir.c_str(), NULL)) { DWORD errorCode = GetLastError(); if (errorCode && errorCode != ERROR_ALREADY_EXISTS) { writeLog(L"Error: failed to create dir '" + forcedir + L"'.."); updateError(L"Failed to create directory", errorCode); delFolder(); return false; } writeLog(L"Already exists!"); } } for (size_t i = 0; i < from.size(); ++i) { wstring fname = from[i], tofname = to[i]; BOOL copyResult; do { writeLog(L"Copying file '" + fname + L"' to '" + tofname + L"'.."); int copyTries = 0; do { copyResult = CopyFile(fname.c_str(), tofname.c_str(), FALSE); if (!copyResult) { ++copyTries; Sleep(100); } else { break; } } while (copyTries < 100); if (!copyResult) { writeLog(L"Error: failed to copy, asking to retry.."); WCHAR errMsg[2048]; wsprintf(errMsg, L"Failed to update Telegram :(\n%s is not accessible.", tofname.c_str()); if (MessageBox(0, errMsg, L"Update error!", MB_ICONERROR | MB_RETRYCANCEL) != IDRETRY) { delFolder(); return false; } } } while (!copyResult); } writeLog(L"Update succeed! Clearing folder.."); delFolder(); return true; } void updateRegistry() { if (versionNum && versionNum != 0x7FFFFFFF) { writeLog(L"Updating registry.."); versionStr[versionLen / 2] = 0; HKEY rkey; LSTATUS status = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{53F49750-6209-4FBF-9CA8-7A333C87D1ED}_is1", 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &rkey); if (status == ERROR_SUCCESS) { writeLog(L"Checking registry install location.."); static const int bufSize = 4096; DWORD locationType, locationSize = bufSize * 2; WCHAR locationStr[bufSize], exp[bufSize]; if (RegQueryValueEx(rkey, L"InstallLocation", 0, &locationType, (BYTE*)locationStr, &locationSize) == ERROR_SUCCESS) { locationSize /= 2; if (locationStr[locationSize - 1]) { locationStr[locationSize++] = 0; } if (locationType == REG_EXPAND_SZ) { DWORD copy = ExpandEnvironmentStrings(locationStr, exp, bufSize); if (copy <= bufSize) { memcpy(locationStr, exp, copy * sizeof(WCHAR)); } } if (locationType == REG_EXPAND_SZ || locationType == REG_SZ) { if (PathCanonicalize(exp, locationStr)) { memcpy(locationStr, exp, bufSize * sizeof(WCHAR)); if (GetFullPathName(L".", bufSize, exp, 0) < bufSize) { wstring installpath = locationStr, mypath = exp; if (installpath == mypath + L"\\" || true) { // always update reg info, if we found it WCHAR nameStr[bufSize], dateStr[bufSize], publisherStr[bufSize], icongroupStr[bufSize]; SYSTEMTIME stLocalTime; GetLocalTime(&stLocalTime); RegSetValueEx(rkey, L"DisplayVersion", 0, REG_SZ, (const BYTE*)versionStr, ((versionLen / 2) + 1) * sizeof(WCHAR)); wsprintf(nameStr, L"Telegram Desktop"); RegSetValueEx(rkey, L"DisplayName", 0, REG_SZ, (const BYTE*)nameStr, (wcslen(nameStr) + 1) * sizeof(WCHAR)); wsprintf(publisherStr, L""); RegSetValueEx(rkey, L"Publisher", 0, REG_SZ, (const BYTE*)publisherStr, (wcslen(publisherStr) + 1) * sizeof(WCHAR)); wsprintf(icongroupStr, L"Telegram Desktop"); RegSetValueEx(rkey, L"Inno Setup: Icon Group", 0, REG_SZ, (const BYTE*)icongroupStr, (wcslen(icongroupStr) + 1) * sizeof(WCHAR)); wsprintf(dateStr, L"%04d%02d%02d", stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay); RegSetValueEx(rkey, L"InstallDate", 0, REG_SZ, (const BYTE*)dateStr, (wcslen(dateStr) + 1) * sizeof(WCHAR)); const WCHAR *appURL = L"https://desktop.telegram.org"; RegSetValueEx(rkey, L"HelpLink", 0, REG_SZ, (const BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR)); RegSetValueEx(rkey, L"URLInfoAbout", 0, REG_SZ, (const BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR)); RegSetValueEx(rkey, L"URLUpdateInfo", 0, REG_SZ, (const BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR)); } } } } } RegCloseKey(rkey); } } } int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdParamarg, int cmdShow) { base::Platform::InitDynamicLibraries(); openLog(); _oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter); // CAPIHook apiHook("kernel32.dll", "SetUnhandledExceptionFilter", (PROC)RedirectedSetUnhandledExceptionFilter); writeLog(L"Updaters started.."); LPWSTR *args; int argsCount; bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false; args = CommandLineToArgvW(GetCommandLine(), &argsCount); if (args) { for (int i = 1; i < argsCount; ++i) { writeLog(std::wstring(L"Argument: ") + args[i]); if (equal(args[i], L"-update")) { needupdate = true; } else if (equal(args[i], L"-autostart")) { autostart = true; } else if (equal(args[i], L"-debug")) { debug = _debug = true; openLog(); } else if (equal(args[i], L"-startintray")) { startintray = true; } else if (equal(args[i], L"-writeprotected") && ++i < argsCount) { writeLog(std::wstring(L"Argument: ") + args[i]); writeprotected = true; updateTo = args[i]; for (int j = 0, l = updateTo.size(); j < l; ++j) { if (updateTo[j] == L'/') { updateTo[j] = L'\\'; } } } else if (equal(args[i], L"-workdir") && ++i < argsCount) { writeLog(std::wstring(L"Argument: ") + args[i]); customWorkingDir = args[i]; } else if (equal(args[i], L"-key") && ++i < argsCount) { writeLog(std::wstring(L"Argument: ") + args[i]); customKeyFile = args[i]; } else if (equal(args[i], L"-exename") && ++i < argsCount) { writeLog(std::wstring(L"Argument: ") + args[i]); exeName = args[i]; for (int j = 0, l = exeName.size(); j < l; ++j) { if (exeName[j] == L'/' || exeName[j] == L'\\') { exeName = L"Telegram.exe"; break; } } } } if (exeName.empty()) { exeName = L"Telegram.exe"; } if (needupdate) writeLog(L"Need to update!"); if (autostart) writeLog(L"From autostart!"); if (writeprotected) writeLog(L"Write Protected folder!"); if (!customWorkingDir.empty()) writeLog(L"Will pass custom working dir: " + customWorkingDir); updaterName = args[0]; writeLog(L"Updater name is: " + updaterName); if (updaterName.size() > 11) { if (equal(updaterName.substr(updaterName.size() - 11), L"Updater.exe")) { updaterDir = updaterName.substr(0, updaterName.size() - 11); writeLog(L"Updater dir is: " + updaterDir); if (!writeprotected) { updateTo = updaterDir; } writeLog(L"Update to: " + updateTo); if (needupdate && update()) { updateRegistry(); } if (writeprotected) { // if we can't clear all tupdates\ready (Updater.exe is there) - clear only version if (DeleteFile(L"tupdates\\temp\\tdata\\version") || DeleteFile(L"tupdates\\ready\\tdata\\version")) { writeLog(L"Version file deleted!"); } else { writeLog(L"Error: could not delete version file"); } } } else { writeLog(L"Error: bad exe name!"); } } else { writeLog(L"Error: short exe name!"); } LocalFree(args); } else { writeLog(L"Error: No command line arguments!"); } wstring targs; if (autostart) targs += L" -autostart"; if (debug) targs += L" -debug"; if (startintray) targs += L" -startintray"; if (!customWorkingDir.empty()) { targs += L" -workdir \"" + customWorkingDir + L"\""; } if (!customKeyFile.empty()) { targs += L" -key \"" + customKeyFile + L"\""; } writeLog(L"Result arguments: " + targs); bool executed = false; if (writeprotected) { // run un-elevated writeLog(L"Trying to run un-elevated by temp.lnk"); HRESULT hres = CoInitialize(0); if (SUCCEEDED(hres)) { IShellLink* psl; HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); if (SUCCEEDED(hres)) { IPersistFile* ppf; wstring exe = updateTo + exeName, dir = updateTo; psl->SetArguments((targs.size() ? targs.substr(1) : targs).c_str()); psl->SetPath(exe.c_str()); psl->SetWorkingDirectory(dir.c_str()); psl->SetDescription(L""); hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); if (SUCCEEDED(hres)) { wstring lnk = L"tupdates\\temp\\temp.lnk"; hres = ppf->Save(lnk.c_str(), TRUE); if (!SUCCEEDED(hres)) { lnk = L"tupdates\\ready\\temp.lnk"; // old hres = ppf->Save(lnk.c_str(), TRUE); } ppf->Release(); if (SUCCEEDED(hres)) { writeLog(L"Executing un-elevated through link.."); ShellExecute(0, 0, L"explorer.exe", lnk.c_str(), 0, SW_SHOWNORMAL); executed = true; } else { writeLog(L"Error: ppf->Save failed"); } } else { writeLog(L"Error: Could not create interface IID_IPersistFile"); } psl->Release(); } else { writeLog(L"Error: could not create instance of IID_IShellLink"); } CoUninitialize(); } else { writeLog(L"Error: Could not initialize COM"); } } if (!executed) { ShellExecute(0, 0, (updateTo + exeName).c_str(), (L"-noupdate" + targs).c_str(), 0, SW_SHOWNORMAL); } writeLog(L"Executed '" + exeName + L"', closing log and quitting.."); closeLog(); return 0; } static const WCHAR *_programName = L"Telegram Desktop"; // folder in APPDATA, if current path is unavailable for writing static const WCHAR *_exeName = L"Updater.exe"; LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter = 0; typedef BOOL (FAR STDAPICALLTYPE *t_miniDumpWriteDump)( _In_ HANDLE hProcess, _In_ DWORD ProcessId, _In_ HANDLE hFile, _In_ MINIDUMP_TYPE DumpType, _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam ); t_miniDumpWriteDump miniDumpWriteDump = 0; HANDLE _generateDumpFileAtPath(const WCHAR *path) { static const int maxFileLen = MAX_PATH * 10; WCHAR szPath[maxFileLen]; wsprintf(szPath, L"%stdata\\", path); if (!CreateDirectory(szPath, NULL)) { if (GetLastError() != ERROR_ALREADY_EXISTS) { return 0; } } wsprintf(szPath, L"%sdumps\\", path); if (!CreateDirectory(szPath, NULL)) { if (GetLastError() != ERROR_ALREADY_EXISTS) { return 0; } } WCHAR szFileName[maxFileLen]; WCHAR szExeName[maxFileLen]; wcscpy_s(szExeName, _exeName); WCHAR *dotFrom = wcschr(szExeName, WCHAR(L'.')); if (dotFrom) { wsprintf(dotFrom, L""); } SYSTEMTIME stLocalTime; GetLocalTime(&stLocalTime); wsprintf( szFileName, L"%s%s-%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp", szPath, szExeName, updaterVersionStr, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, GetCurrentProcessId(), GetCurrentThreadId()); return CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); } void _generateDump(EXCEPTION_POINTERS* pExceptionPointers) { static const int maxFileLen = MAX_PATH * 10; closeLog(); HMODULE hDll = LoadLibrary(L"DBGHELP.DLL"); if (!hDll) return; miniDumpWriteDump = (t_miniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump"); if (!miniDumpWriteDump) return; HANDLE hDumpFile = 0; WCHAR szPath[maxFileLen]; DWORD len = GetModuleFileName(GetModuleHandle(0), szPath, maxFileLen); if (!len) return; WCHAR *pathEnd = szPath + len; if (!_wcsicmp(pathEnd - wcslen(_exeName), _exeName)) { wsprintf(pathEnd - wcslen(_exeName), L""); hDumpFile = _generateDumpFileAtPath(szPath); } if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) { WCHAR wstrPath[maxFileLen]; DWORD wstrPathLen = GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen); if (wstrPathLen) { wsprintf(wstrPath + wstrPathLen, L"\\%s\\", _programName); hDumpFile = _generateDumpFileAtPath(wstrPath); } } if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) { return; } MINIDUMP_EXCEPTION_INFORMATION ExpParam = {0}; ExpParam.ThreadId = GetCurrentThreadId(); ExpParam.ExceptionPointers = pExceptionPointers; ExpParam.ClientPointers = TRUE; miniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL); } LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers) { _generateDump(pExceptionPointers); return _oldWndExceptionFilter ? (*_oldWndExceptionFilter)(pExceptionPointers) : EXCEPTION_CONTINUE_SEARCH; } // see http://www.codeproject.com/Articles/154686/SetUnhandledExceptionFilter-and-the-C-C-Runtime-Li LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) { // When the CRT calls SetUnhandledExceptionFilter with NULL parameter // our handler will not get removed. _oldWndExceptionFilter = lpTopLevelExceptionFilter; return 0; } ================================================ FILE: Telegram/SourceFiles/api/api_as_copy.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_as_copy.h" #include "api/api_common.h" #include "api/api_sending.h" #include "api/api_text_entities.h" #include "apiwrap.h" #include "base/random.h" #include "base/unixtime.h" #include "chat_helpers/message_field.h" #include "data/data_channel.h" #include "data/data_document.h" #include "data/data_drafts.h" #include "data/data_histories.h" #include "data/data_photo.h" #include "data/data_session.h" #include "history/history.h" #include "history/history_item.h" #include "main/main_session.h" namespace Api::AsCopy { namespace { MTPInputSingleMedia PrepareAlbumItemMedia( not_null item, const MTPInputMedia &media, uint64 randomId, bool emptyText, TextWithTags comment) { auto commentEntities = TextWithEntities { comment.text, TextUtilities::ConvertTextTagsToEntities(comment.tags) }; auto caption = item->originalText(); TextUtilities::Trim(caption); auto sentEntities = Api::EntitiesToMTP( &item->history()->session(), emptyText ? commentEntities.entities : caption.entities, Api::ConvertOption::SkipLocal); const auto flags = !sentEntities.v.isEmpty() ? MTPDinputSingleMedia::Flag::f_entities : MTPDinputSingleMedia::Flag(0); return MTP_inputSingleMedia( MTP_flags(flags), media, MTP_long(randomId), MTP_string(emptyText ? commentEntities.text : caption.text), sentEntities); } MTPinputMedia InputMediaFromItem(not_null i) { if (const auto document = i->media()->document()) { return MTP_inputMediaDocument( MTP_flags(MTPDinputMediaDocument::Flag(0)), document->mtpInput(), document->goodThumbnailPhoto() ? document->goodThumbnailPhoto()->mtpInput() : MTPInputPhoto(), MTP_int(0), MTP_int(0), MTPstring()); } else if (const auto photo = i->media()->photo()) { return MTP_inputMediaPhoto( MTP_flags(MTPDinputMediaPhoto::Flag(0)), photo->mtpInput(), MTP_int(0), MTPInputDocument()); } else { return MTP_inputMediaEmpty(); } } FullReplyTo ReplyToIdFromDraft(not_null peer) { const auto history = peer->owner().history(peer); const auto replyTo = [&]() -> FullReplyTo { if (const auto localDraft = history->localDraft(0, 0)) { return localDraft->reply; } else if (const auto cloudDraft = history->cloudDraft(0, 0)) { return cloudDraft->reply; } else { return {}; } }(); if (replyTo) { history->clearCloudDraft(0, 0); history->clearLocalDraft(0, 0); peer->session().api().request( MTPmessages_SaveDraft( MTP_flags(MTPmessages_SaveDraft::Flags(0)), MTP_inputReplyToStory(MTP_inputPeerEmpty(), MTPint()), history->peer->input(), MTPstring(), MTPVector(), MTP_inputMediaEmpty(), MTP_long(0), SuggestToMTP({}) )).send(); } return replyTo; } } // namespace void SendAlbumFromItems( HistoryItemsList items, ToSend &&toSend, bool andDelete) { if (items.empty()) { return; } const auto history = items.front()->history(); const auto ids = history->owner().itemsToIds(items); auto medias = QVector(); for (const auto &i : items) { medias.push_back(PrepareAlbumItemMedia( i, InputMediaFromItem(i), base::RandomValue(), toSend.emptyText, medias.empty() ? toSend.comment : TextWithTags())); } auto &api = history->owner().session().api(); for (const auto &peer : toSend.peers) { const auto replyTo = ReplyToIdFromDraft(peer); const auto flags = MTPmessages_SendMultiMedia::Flags(0) | (replyTo ? MTPmessages_SendMultiMedia::Flag::f_reply_to : MTPmessages_SendMultiMedia::Flag(0)) | (toSend.silent ? MTPmessages_SendMultiMedia::Flag::f_silent : MTPmessages_SendMultiMedia::Flag(0)) | (toSend.scheduled ? MTPmessages_SendMultiMedia::Flag::f_schedule_date : MTPmessages_SendMultiMedia::Flag(0)); api.request(MTPmessages_SendMultiMedia( MTP_flags(flags), peer->input(), ReplyToForMTP(history, replyTo), MTP_vector(medias), MTP_int(toSend.scheduled), MTP_inputPeerEmpty(), MTPInputQuickReplyShortcut(), MTP_long(0), MTP_long(0) )).done([=](const MTPUpdates &result) { history->owner().session().api().applyUpdates(result); if (andDelete) { history->owner().histories().deleteMessages(ids, true); history->owner().sendHistoryChangeNotifications(); } }).fail([=](const MTP::Error &error) { }).send(); } } void GuardedSendExistingAlbumFromItem( not_null item, Api::AsCopy::ToSend &&toSend) { if (!item->groupId()) { return; } const auto items = item->history()->owner().groups().find(item)->items; UpdateFileRef( items, [=] { SendAlbumFromItems(items, base::duplicate(toSend), false); }, [](QString){}); } void SendExistingMediaFromItem( not_null item, Api::AsCopy::ToSend &&toSend) { for (const auto peer : toSend.peers) { const auto history = peer->owner().history(peer); auto message = MessageToSend(SendAction{ history }); if (!item->media()) { message.textWithTags = PrepareEditText(item); history->session().api().sendMessage(std::move(message)); continue; } message.textWithTags = toSend.emptyText ? toSend.comment : PrepareEditText(item); message.action.options.silent = toSend.silent; message.action.options.scheduled = toSend.scheduled; message.action.replyTo = ReplyToIdFromDraft(peer); if (const auto document = item->media()->document()) { Api::SendExistingDocument( std::move(message), document, item->fullId()); } else if (const auto photo = item->media()->photo()) { Api::SendExistingPhoto(std::move(message), photo, item->fullId()); } } } void UpdateFileRef( HistoryItemsList list, Fn success, Fn fail) { if (list.empty()) { return; } const auto history = list.front()->history(); auto inputMessages = ranges::views::all( list ) | ranges::views::transform([&](const auto &item) { return MTP_inputMessageID(MTP_int(item->id)); }) | ranges::to>(); const auto receive = [=](const MTPmessages_Messages &result) { result.match([&](const MTPDmessages_messagesNotModified &) { fail("MTPDmessages_messagesNotModified"); }, [&](const auto &d) { auto good = true; for (const auto &tlMessage : d.vmessages().v) { tlMessage.match([&](const MTPDmessage &d) { history->session().data().updateExistingMessage(d); }, [&](const auto &) { good = false; fail("MTPDmessageService or MTPDmessageEmpty"); }); } if (good) { success(); } }); }; const auto receiveError = [=](auto error) { fail("Get Message error: " + error.type()); }; if (const auto channel = history->peer->asChannel()) { history->session().api().request( MTPchannels_GetMessages( channel->inputChannel(), MTP_vector(std::move(inputMessages))) ).done(receive).fail(receiveError).send(); } else { history->session().api().request( MTPmessages_GetMessages( MTP_vector(std::move(inputMessages))) ).done(receive).fail(receiveError).send(); } } } // namespace Api::AsCopy ================================================ FILE: Telegram/SourceFiles/api/api_as_copy.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once class HistoryItem; class PeerData; struct TextWithTags; namespace Api::AsCopy { struct ToSend { std::vector> peers; TextWithTags comment; bool emptyText = false; bool silent = false; TimeId scheduled = 0; }; void GuardedSendExistingAlbumFromItem( not_null item, ToSend &&toSend); void SendExistingMediaFromItem(not_null item, ToSend &&toSend); void SendAlbumFromItems( HistoryItemsList items, ToSend &&toSend, bool andDelete); void UpdateFileRef( HistoryItemsList list, Fn success, Fn fail); } // namespace Api::AsCopy ================================================ FILE: Telegram/SourceFiles/api/api_attached_stickers.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_attached_stickers.h" #include "apiwrap.h" #include "ui/boxes/confirm_box.h" #include "boxes/sticker_set_box.h" #include "boxes/stickers_box.h" #include "data/data_document.h" #include "data/data_photo.h" #include "lang/lang_keys.h" #include "window/window_session_controller.h" namespace Api { AttachedStickers::AttachedStickers(not_null api) : _api(&api->instance()) { } void AttachedStickers::request( not_null controller, MTPmessages_GetAttachedStickers &&mtpRequest) { const auto weak = base::make_weak(controller); _api.request(_requestId).cancel(); _requestId = _api.request( std::move(mtpRequest) ).done([=](const MTPVector &result) { _requestId = 0; const auto strongController = weak.get(); if (!strongController) { return; } if (result.v.isEmpty()) { strongController->show( Ui::MakeInformBox(tr::lng_stickers_not_found())); return; } else if (result.v.size() > 1) { strongController->show( Box(strongController->uiShow(), result.v)); return; } // Single attached sticker pack. const auto data = result.v.front().match([&](const auto &data) { return &data.vset().data(); }); const auto setId = (data->vid().v && data->vaccess_hash().v) ? StickerSetIdentifier{ .id = data->vid().v, .accessHash = data->vaccess_hash().v } : StickerSetIdentifier{ .shortName = qs(data->vshort_name()) }; strongController->show(Box( strongController->uiShow(), setId, (data->is_emojis() ? Data::StickersType::Emoji : data->is_masks() ? Data::StickersType::Masks : Data::StickersType::Stickers))); }).fail([=] { _requestId = 0; if (const auto strongController = weak.get()) { strongController->show( Ui::MakeInformBox(tr::lng_stickers_not_found())); } }).send(); } void AttachedStickers::requestAttachedStickerSets( not_null controller, not_null photo) { request( controller, MTPmessages_GetAttachedStickers( MTP_inputStickeredMediaPhoto(photo->mtpInput()))); } void AttachedStickers::requestAttachedStickerSets( not_null controller, not_null document) { request( controller, MTPmessages_GetAttachedStickers( MTP_inputStickeredMediaDocument(document->mtpInput()))); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_attached_stickers.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "mtproto/sender.h" class ApiWrap; class DocumentData; class PhotoData; namespace Window { class SessionController; } // namespace Window namespace Api { class AttachedStickers final { public: explicit AttachedStickers(not_null api); void requestAttachedStickerSets( not_null controller, not_null photo); void requestAttachedStickerSets( not_null controller, not_null document); private: void request( not_null controller, MTPmessages_GetAttachedStickers &&mtpRequest); MTP::Sender _api; mtpRequestId _requestId = 0; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_authorizations.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_authorizations.h" #include "apiwrap.h" #include "base/unixtime.h" #include "core/application.h" #include "core/changelogs.h" #include "core/core_settings.h" #include "lang/lang_keys.h" #include "main/main_app_config.h" #include "main/main_session_settings.h" #include "main/main_session.h" namespace Api { namespace { constexpr auto TestApiId = 17349; constexpr auto SnapApiId = 611335; constexpr auto DesktopApiId = 2040; Authorizations::Entry ParseEntry(const MTPDauthorization &data) { auto result = Authorizations::Entry(); result.hash = data.is_current() ? 0 : data.vhash().v; result.incomplete = data.is_password_pending(); result.callsDisabled = data.is_call_requests_disabled(); const auto apiId = result.apiId = data.vapi_id().v; const auto isTest = (apiId == TestApiId); const auto isDesktop = (apiId == DesktopApiId) || (apiId == SnapApiId) || isTest; const auto appName = isDesktop ? u"Telegram Desktop%1"_q.arg(isTest ? " (GitHub)" : QString()) : qs(data.vapp_name());// + u" for "_q + qs(d.vplatform()); const auto appVer = [&] { const auto version = qs(data.vapp_version()); if (isDesktop) { const auto verInt = version.toInt(); if (version == QString::number(verInt)) { return Core::FormatVersionDisplay(verInt); } } else { if (const auto index = version.indexOf('('); index >= 0) { return version.mid(index); } } return version; }(); result.name = result.hash ? qs(data.vdevice_model()) : Core::App().settings().deviceModel(); const auto country = qs(data.vcountry()); //const auto platform = qs(data.vplatform()); //const auto &countries = countriesByISO2(); //const auto j = countries.constFind(country); //if (j != countries.cend()) { // country = QString::fromUtf8(j.value()->name); //} result.system = qs(data.vsystem_version()); result.platform = qs(data.vplatform()); result.activeTime = data.vdate_active().v ? data.vdate_active().v : data.vdate_created().v; result.info = QString("%1%2").arg( appName, appVer.isEmpty() ? QString() : (' ' + appVer)); result.ip = qs(data.vip()); result.active = result.hash ? Authorizations::ActiveDateString(result.activeTime) : tr::lng_status_online(tr::now); result.location = country; return result; } } // namespace Authorizations::Authorizations(not_null api) : _api(&api->instance()) , _autoconfirmPeriod([=] { constexpr auto kFallbackCount = 604800; return api->session().appConfig().get( u"authorization_autoconfirm_period"_q, kFallbackCount); }) , _saveUnreviewed([=] { api->session().settings().setUnreviewed(_unreviewed); api->session().saveSettingsDelayed(); }) { _unreviewed = api->session().settings().unreviewed(); crl::on_main(&api->session(), [=] { removeExpiredUnreviewed(); }); Core::App().settings().deviceModelChanges( ) | rpl::on_next([=](const QString &model) { auto changed = false; for (auto &entry : _list) { if (!entry.hash) { entry.name = model; changed = true; } } if (changed) { _listChanges.fire({}); } }, _lifetime); if (Core::App().settings().disableCallsLegacy()) { toggleCallsDisabledHere(true); } } void Authorizations::reload() { if (_requestId) { return; } _requestId = _api.request(MTPaccount_GetAuthorizations( )).done([=](const MTPaccount_Authorizations &result) { _requestId = 0; _lastReceived = crl::now(); const auto &data = result.data(); _ttlDays = data.vauthorization_ttl_days().v; _list = ranges::views::all( data.vauthorizations().v ) | ranges::views::transform([](const MTPAuthorization &auth) { return ParseEntry(auth.data()); }) | ranges::to; removeExpiredUnreviewed(); refreshCallsDisabledHereFromCloud(); _listChanges.fire({}); }).fail([=] { _requestId = 0; }).send(); } void Authorizations::cancelCurrentRequest() { _api.request(base::take(_requestId)).cancel(); } void Authorizations::refreshCallsDisabledHereFromCloud() { const auto that = ranges::find(_list, 0, &Entry::hash); if (that != end(_list) && !_toggleCallsDisabledRequests.contains(0)) { _callsDisabledHere = that->callsDisabled; } } void Authorizations::requestTerminate( Fn &&done, Fn &&fail, std::optional hash) { const auto send = [&](auto request) { _api.request( std::move(request) ).done([=, done = std::move(done)](const MTPBool &result) { done(result); if (mtpIsTrue(result)) { if (hash) { _list.erase( ranges::remove(_list, *hash, &Entry::hash), end(_list)); } else { _list.clear(); } _listChanges.fire({}); } }).fail( std::move(fail) ).send(); }; if (hash) { send(MTPaccount_ResetAuthorization(MTP_long(*hash))); } else { send(MTPauth_ResetAuthorizations()); } } Authorizations::List Authorizations::list() const { return _list; } auto Authorizations::listValue() const -> rpl::producer { return rpl::single( list() ) | rpl::then( _listChanges.events() | rpl::map([=] { return list(); }) ); } rpl::producer Authorizations::totalValue() const { return rpl::single( total() ) | rpl::then( _listChanges.events() | rpl::map([=] { return total(); }) ); } void Authorizations::updateTTL(int days) { _api.request(_ttlRequestId).cancel(); _ttlRequestId = _api.request(MTPaccount_SetAuthorizationTTL( MTP_int(days) )).done([=] { _ttlRequestId = 0; }).fail([=] { _ttlRequestId = 0; }).send(); _ttlDays = days; } rpl::producer Authorizations::ttlDays() const { return _ttlDays.value() | rpl::filter(rpl::mappers::_1 != 0); } void Authorizations::toggleCallsDisabled(uint64 hash, bool disabled) { if (const auto sent = _toggleCallsDisabledRequests.take(hash)) { _api.request(*sent).cancel(); } using Flag = MTPaccount_ChangeAuthorizationSettings::Flag; const auto id = _api.request(MTPaccount_ChangeAuthorizationSettings( MTP_flags(Flag::f_call_requests_disabled), MTP_long(hash), MTPBool(), // encrypted_requests_disabled MTP_bool(disabled) )).done([=] { _toggleCallsDisabledRequests.remove(hash); }).fail([=] { _toggleCallsDisabledRequests.remove(hash); }).send(); _toggleCallsDisabledRequests.emplace(hash, id); if (!hash) { _callsDisabledHere = disabled; } } bool Authorizations::callsDisabledHere() const { return _callsDisabledHere.current(); } rpl::producer Authorizations::callsDisabledHereValue() const { return _callsDisabledHere.value(); } rpl::producer Authorizations::callsDisabledHereChanges() const { return _callsDisabledHere.changes(); } QString Authorizations::ActiveDateString(TimeId active) { const auto now = QDateTime::currentDateTime(); const auto lastTime = base::unixtime::parse(active); const auto nowDate = now.date(); const auto lastDate = lastTime.date(); return (lastDate == nowDate) ? QLocale().toString(lastTime.time(), QLocale::ShortFormat) : (lastDate.year() == nowDate.year() && lastDate.weekNumber() == nowDate.weekNumber()) ? langDayOfWeek(lastDate) : QLocale().toString(lastDate, QLocale::ShortFormat); } int Authorizations::total() const { return ranges::count_if( _list, ranges::not_fn(&Entry::incomplete)); } crl::time Authorizations::lastReceivedTime() { return _lastReceived; } const std::vector &Authorizations::unreviewed() { removeExpiredUnreviewed(); return _unreviewed; } void Authorizations::removeExpiredUnreviewed() { const auto now = base::unixtime::now(); const auto period = _autoconfirmPeriod(); const auto oldSize = _unreviewed.size(); _unreviewed.erase( std::remove_if(_unreviewed.begin(), _unreviewed.end(), [=](const auto &auth) { return (now - auth.date) >= period; }), _unreviewed.end()); if (_unreviewed.size() != oldSize) { _saveUnreviewed(); } } void Authorizations::review(const std::vector &hashes, bool confirm) { for (const auto hash : hashes) { if (const auto sent = _reviewRequests.take(hash)) { _api.request(*sent).cancel(); } } const auto checkComplete = [=] { if (_reviewRequests.empty()) { _saveUnreviewed(); _unreviewedChanges.fire({}); } }; for (const auto hash : hashes) { const auto removeFromUnreviewed = [=] { _unreviewed.erase( std::remove_if(_unreviewed.begin(), _unreviewed.end(), [hash](const auto &auth) { return auth.hash == hash; }), _unreviewed.end()); _reviewRequests.remove(hash); checkComplete(); }; if (confirm) { using Flag = MTPaccount_ChangeAuthorizationSettings::Flag; const auto id = _api.request(MTPaccount_ChangeAuthorizationSettings( MTP_flags(Flag::f_confirmed), MTP_long(hash), MTPBool(), // encrypted_requests_disabled MTPBool() // call_requests_disabled )).done([=] { removeFromUnreviewed(); }).fail([=] { removeFromUnreviewed(); }).send(); _reviewRequests.emplace(hash, id); } else { const auto id = _api.request(MTPaccount_ResetAuthorization( MTP_long(hash) )).done([=](const MTPBool &result) { if (mtpIsTrue(result)) { _list.erase( ranges::remove(_list, hash, &Entry::hash), end(_list)); _listChanges.fire({}); } removeFromUnreviewed(); }).fail([=] { removeFromUnreviewed(); }).send(); _reviewRequests.emplace(hash, id); } } } rpl::producer<> Authorizations::unreviewedChanges() const { return _unreviewedChanges.events(); } void Authorizations::apply(const MTPUpdate &update) { removeExpiredUnreviewed(); update.match([&](const MTPDupdateNewAuthorization &data) { auto unreviewed = Data::UnreviewedAuth{ .hash = data.vhash().v, .unconfirmed = data.is_unconfirmed(), .date = data.vdate().value_or_empty(), .device = qs(data.vdevice().value_or_empty()), .location = qs(data.vlocation().value_or_empty()) }; if (!unreviewed.unconfirmed) { const auto hash = unreviewed.hash; const auto was = _unreviewed.size(); _unreviewed.erase( std::remove_if( _unreviewed.begin(), _unreviewed.end(), [hash](const auto &auth) { return auth.hash == hash; }), _unreviewed.end()); if (was != _unreviewed.size()) { _saveUnreviewed(); _unreviewedChanges.fire({}); } return; } for (auto &auth : _unreviewed) { if (auth.hash == unreviewed.hash) { auth = std::move(unreviewed); _saveUnreviewed(); _unreviewedChanges.fire({}); return; } } _unreviewed.push_back(std::move(unreviewed)); _saveUnreviewed(); _unreviewedChanges.fire({}); }, [](auto&&) { Unexpected("Update in Authorizations::apply."); }); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_authorizations.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "data/data_authorization.h" #include "mtproto/sender.h" class ApiWrap; namespace Api { class Authorizations final { public: explicit Authorizations(not_null api); struct Entry { uint64 hash = 0; bool incomplete = false; bool callsDisabled = false; int apiId = 0; TimeId activeTime = 0; QString name, active, info, ip, location, system, platform; }; using List = std::vector; void reload(); void cancelCurrentRequest(); void requestTerminate( Fn &&done, Fn &&fail, std::optional hash = std::nullopt); void apply(const MTPUpdate &update); [[nodiscard]] crl::time lastReceivedTime(); [[nodiscard]] List list() const; [[nodiscard]] rpl::producer listValue() const; [[nodiscard]] int total() const; [[nodiscard]] rpl::producer totalValue() const; [[nodiscard]] const std::vector &unreviewed(); [[nodiscard]] rpl::producer<> unreviewedChanges() const; void review(const std::vector &hashes, bool confirm); void updateTTL(int days); [[nodiscard]] rpl::producer ttlDays() const; void toggleCallsDisabledHere(bool disabled) { toggleCallsDisabled(0, disabled); } void toggleCallsDisabled(uint64 hash, bool disabled); [[nodiscard]] bool callsDisabledHere() const; [[nodiscard]] rpl::producer callsDisabledHereValue() const; [[nodiscard]] rpl::producer callsDisabledHereChanges() const; [[nodiscard]] static QString ActiveDateString(TimeId active); private: void refreshCallsDisabledHereFromCloud(); void removeExpiredUnreviewed(); MTP::Sender _api; mtpRequestId _requestId = 0; List _list; rpl::event_stream<> _listChanges; Fn _autoconfirmPeriod; std::vector _unreviewed; rpl::event_stream<> _unreviewedChanges; Fn _saveUnreviewed; mtpRequestId _ttlRequestId = 0; rpl::variable _ttlDays = 0; base::flat_map _toggleCallsDisabledRequests; base::flat_map _reviewRequests; rpl::variable _callsDisabledHere; crl::time _lastReceived = 0; rpl::lifetime _lifetime; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_blocked_peers.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_blocked_peers.h" #include "apiwrap.h" #include "base/unixtime.h" #include "data/data_changes.h" #include "data/data_peer.h" #include "data/data_peer_id.h" #include "data/data_session.h" #include "main/main_session.h" namespace Api { namespace { constexpr auto kBlockedFirstSlice = 16; constexpr auto kBlockedPerPage = 40; BlockedPeers::Slice TLToSlice( const MTPcontacts_Blocked &blocked, Data::Session &owner) { const auto create = [&](int count, const QVector &list) { auto slice = BlockedPeers::Slice(); slice.total = std::max(count, int(list.size())); slice.list.reserve(list.size()); for (const auto &contact : list) { contact.match([&](const MTPDpeerBlocked &data) { slice.list.push_back({ .id = peerFromMTP(data.vpeer_id()), .date = data.vdate().v, }); }); } return slice; }; return blocked.match([&](const MTPDcontacts_blockedSlice &data) { owner.processUsers(data.vusers()); owner.processChats(data.vchats()); return create(data.vcount().v, data.vblocked().v); }, [&](const MTPDcontacts_blocked &data) { owner.processUsers(data.vusers()); owner.processChats(data.vchats()); return create(0, data.vblocked().v); }); } } // namespace BlockedPeers::BlockedPeers(not_null api) : _session(&api->session()) , _api(&api->instance()) { } bool BlockedPeers::Slice::Item::operator==(const Item &other) const { return (id == other.id) && (date == other.date); } bool BlockedPeers::Slice::Item::operator!=(const Item &other) const { return !(*this == other); } bool BlockedPeers::Slice::operator==(const BlockedPeers::Slice &other) const { return (total == other.total) && (list == other.list); } bool BlockedPeers::Slice::operator!=(const BlockedPeers::Slice &other) const { return !(*this == other); } void BlockedPeers::block(not_null peer) { if (peer->isBlocked()) { _session->changes().peerUpdated( peer, Data::PeerUpdate::Flag::IsBlocked); return; } else if (blockAlreadySent(peer, true)) { return; } const auto requestId = _api.request(MTPcontacts_Block( MTP_flags(0), peer->input() )).done([=] { const auto data = _blockRequests.take(peer); peer->setIsBlocked(true); if (_slice) { _slice->list.insert( _slice->list.begin(), { peer->id, base::unixtime::now() }); ++_slice->total; _changes.fire_copy(*_slice); } if (data) { for (const auto &callback : data->callbacks) { callback(false); } } }).fail([=] { if (const auto data = _blockRequests.take(peer)) { for (const auto &callback : data->callbacks) { callback(false); } } }).send(); _blockRequests.emplace(peer, Request{ .requestId = requestId, .blocking = true, }); } void BlockedPeers::unblock( not_null peer, Fn done, bool force) { if (!force && !peer->isBlocked()) { _session->changes().peerUpdated( peer, Data::PeerUpdate::Flag::IsBlocked); return; } else if (blockAlreadySent(peer, false, done)) { return; } const auto requestId = _api.request(MTPcontacts_Unblock( MTP_flags(0), peer->input() )).done([=] { const auto data = _blockRequests.take(peer); peer->setIsBlocked(false); if (_slice) { auto &list = _slice->list; for (auto i = list.begin(); i != list.end(); ++i) { if (i->id == peer->id) { list.erase(i); break; } } if (_slice->total > list.size()) { --_slice->total; } _changes.fire_copy(*_slice); } if (data) { for (const auto &callback : data->callbacks) { callback(true); } } }).fail([=] { if (const auto data = _blockRequests.take(peer)) { for (const auto &callback : data->callbacks) { callback(false); } } }).send(); const auto i = _blockRequests.emplace(peer, Request{ .requestId = requestId, .blocking = false, }).first; if (done) { i->second.callbacks.push_back(std::move(done)); } } bool BlockedPeers::blockAlreadySent( not_null peer, bool blocking, Fn done) { const auto i = _blockRequests.find(peer); if (i == end(_blockRequests)) { return false; } else if (i->second.blocking == blocking) { if (done) { i->second.callbacks.push_back(std::move(done)); } return true; } const auto callbacks = base::take(i->second.callbacks); _blockRequests.erase(i); for (const auto &callback : callbacks) { callback(false); } return false; } void BlockedPeers::reload() { if (_requestId) { return; } request(0, [=](Slice &&slice) { if (!_slice || *_slice != slice) { _slice = slice; _changes.fire(std::move(slice)); } }); } auto BlockedPeers::slice() -> rpl::producer { if (!_slice) { reload(); } return _slice ? _changes.events_starting_with_copy(*_slice) : (_changes.events() | rpl::type_erased); } void BlockedPeers::request(int offset, Fn done) { if (_requestId) { return; } _requestId = _api.request(MTPcontacts_GetBlocked( MTP_flags(0), MTP_int(offset), MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice) )).done([=](const MTPcontacts_Blocked &result) { _requestId = 0; done(TLToSlice(result, _session->data())); }).fail([=] { _requestId = 0; }).send(); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_blocked_peers.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "mtproto/sender.h" class ApiWrap; namespace Main { class Session; } // namespace Main namespace Api { class BlockedPeers final { public: struct Slice { struct Item { PeerId id; TimeId date = 0; bool operator==(const Item &other) const; bool operator!=(const Item &other) const; }; QVector list; int total = 0; bool operator==(const Slice &other) const; bool operator!=(const Slice &other) const; }; explicit BlockedPeers(not_null api); void reload(); rpl::producer slice(); void request(int offset, Fn done); void block(not_null peer); void unblock( not_null peer, Fn done = nullptr, bool force = false); private: struct Request { std::vector> callbacks; mtpRequestId requestId = 0; bool blocking = false; }; [[nodiscard]] bool blockAlreadySent( not_null peer, bool blocking, Fn done = nullptr); const not_null _session; MTP::Sender _api; base::flat_map, Request> _blockRequests; mtpRequestId _requestId = 0; std::optional _slice; rpl::event_stream _changes; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_bot.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_bot.h" #include "apiwrap.h" #include "api/api_cloud_password.h" #include "api/api_send_progress.h" #include "api/api_suggest_post.h" #include "boxes/peers/choose_peer_box.h" #include "boxes/peers/create_managed_bot_box.h" #include "boxes/passcode_box.h" #include "boxes/share_box.h" #include "boxes/url_auth_box.h" #include "lang/lang_keys.h" #include "chat_helpers/bot_command.h" #include "core/core_cloud_password.h" #include "core/click_handler_types.h" #include "data/data_changes.h" #include "data/data_peer.h" #include "data/data_poll.h" #include "data/data_user.h" #include "data/data_session.h" #include "history/history.h" #include "history/history_item.h" #include "history/history_item_components.h" #include "inline_bots/bot_attach_web_view.h" #include "payments/payments_checkout_process.h" #include "payments/payments_non_panel_process.h" #include "main/main_session.h" #include "mainwidget.h" #include "mainwindow.h" #include "window/window_session_controller.h" #include "window/window_peer_menu.h" #include "ui/boxes/confirm_box.h" #include "ui/toast/toast.h" #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" #include "styles/style_chat.h" #include #include #include namespace Api { namespace { void SendBotCallbackData( not_null controller, not_null item, int row, int column, std::optional password, Fn done = nullptr, Fn handleError = nullptr) { if (!item->isRegular()) { return; } const auto history = item->history(); const auto session = &history->session(); const auto owner = &history->owner(); const auto api = &session->api(); const auto bot = item->getMessageBot(); const auto fullId = item->fullId(); const auto getButton = [=] { return HistoryMessageMarkupButton::Get(owner, fullId, row, column); }; const auto button = getButton(); if (!button || button->requestId) { return; } using ButtonType = HistoryMessageMarkupButton::Type; const auto isGame = (button->type == ButtonType::Game); auto flags = MTPmessages_GetBotCallbackAnswer::Flags(0); QByteArray sendData; if (isGame) { flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_game; } else if (button->type == ButtonType::Callback || button->type == ButtonType::CallbackWithPassword) { flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_data; sendData = button->data; } const auto withPassword = password.has_value(); if (withPassword) { flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_password; } const auto weak = base::make_weak(controller); const auto show = controller->uiShow(); button->requestId = api->request(MTPmessages_GetBotCallbackAnswer( MTP_flags(flags), history->peer->input(), MTP_int(item->id), MTP_bytes(sendData), password ? password->result : MTP_inputCheckPasswordEmpty() )).done([=](const MTPmessages_BotCallbackAnswer &result) { const auto guard = gsl::finally([&] { if (done) { done(); } }); const auto item = owner->message(fullId); if (!item) { return; } if (const auto button = getButton()) { button->requestId = 0; owner->requestItemRepaint(item); } const auto &data = result.data(); const auto message = data.vmessage() ? qs(*data.vmessage()) : QString(); const auto link = data.vurl() ? qs(*data.vurl()) : QString(); const auto showAlert = data.is_alert(); if (!message.isEmpty()) { if (!show->valid()) { return; } else if (showAlert) { show->showBox(Ui::MakeInformBox(message)); } else { if (withPassword) { show->hideLayer(); } show->showToast(message); } } else if (!link.isEmpty()) { if (!isGame) { UrlClickHandler::Open(link); return; } BotGameUrlClickHandler(bot, link).onClick({ Qt::LeftButton, QVariant::fromValue(ClickHandlerContext{ .itemId = item->fullId(), .sessionWindow = weak, }), }); session->sendProgressManager().update( history, Api::SendProgressType::PlayGame); } else if (withPassword) { show->hideLayer(); } }).fail([=](const MTP::Error &error) { const auto guard = gsl::finally([&] { if (handleError) { handleError(error.type()); } }); const auto item = owner->message(fullId); if (!item) { return; } // Show error? if (const auto button = getButton()) { button->requestId = 0; owner->requestItemRepaint(item); } }).send(); session->changes().messageUpdated( item, Data::MessageUpdate::Flag::BotCallbackSent ); } void HideSingleUseKeyboard( not_null controller, not_null item) { controller->content()->hideSingleUseKeyboard(item->fullId()); } } // namespace void SendBotCallbackData( not_null controller, not_null item, int row, int column) { SendBotCallbackData(controller, item, row, column, std::nullopt); } void SendBotCallbackDataWithPassword( not_null controller, not_null item, int row, int column) { if (!item->isRegular()) { return; } const auto history = item->history(); const auto session = &history->session(); const auto owner = &history->owner(); const auto api = &session->api(); const auto fullId = item->fullId(); const auto getButton = [=] { return HistoryMessageMarkupButton::Get( owner, fullId, row, column); }; const auto button = getButton(); if (!button || button->requestId) { return; } api->cloudPassword().reload(); const auto weak = base::make_weak(controller); const auto show = controller->uiShow(); SendBotCallbackData(controller, item, row, column, {}, {}, [=]( const QString &error) { auto box = PrePasswordErrorBox( error, session, tr::lng_bots_password_confirm_check_about( tr::now, tr::marked)); if (box) { show->showBox(std::move(box), Ui::LayerOption::CloseOther); } else { auto lifetime = std::make_shared(); button->requestId = -1; api->cloudPassword().state( ) | rpl::take( 1 ) | rpl::on_next([=](const Core::CloudPasswordState &state) mutable { if (lifetime) { base::take(lifetime)->destroy(); } if (const auto button = getButton()) { if (button->requestId == -1) { button->requestId = 0; } } else { return; } auto fields = PasscodeBox::CloudFields::From(state); fields.customTitle = tr::lng_bots_password_confirm_title(); fields.customDescription = tr::lng_bots_password_confirm_description(tr::now); fields.customSubmitButton = tr::lng_passcode_submit(); fields.customCheckCallback = [=]( const Core::CloudPasswordResult &result, base::weak_qptr box) { if (const auto button = getButton()) { if (button->requestId) { return; } } else { return; } if (const auto item = owner->message(fullId)) { const auto strongController = weak.get(); if (!strongController) { return; } SendBotCallbackData(strongController, item, row, column, result, [=] { if (box) { box->closeBox(); } }, [=](const QString &error) { if (box) { box->handleCustomCheckError(error); } }); } }; auto object = Box(session, fields); show->showBox(std::move(object), Ui::LayerOption::CloseOther); }, *lifetime); } }); } bool SwitchInlineBotButtonReceived( not_null controller, const QByteArray &queryWithPeerTypes, UserData *samePeerBot, MsgId samePeerReplyTo) { return controller->content()->notify_switchInlineBotButtonReceived( QString::fromUtf8(queryWithPeerTypes), samePeerBot, samePeerReplyTo); } void ActivateBotCommand(ClickHandlerContext context, int row, int column) { const auto strong = context.sessionWindow.get(); if (!strong) { return; } const auto controller = not_null{ strong }; const auto item = controller->session().data().message(context.itemId); if (!item) { return; } const auto button = HistoryMessageMarkupButton::Get( &item->history()->owner(), item->fullId(), row, column); if (!button) { return; } using ButtonType = HistoryMessageMarkupButton::Type; switch (button->type) { case ButtonType::Default: { // Copy string before passing it to the sending method // because the original button can be destroyed inside. const auto replyTo = item->isRegular() ? item->fullId() : FullMsgId(); controller->content()->sendBotCommand({ .peer = item->history()->peer, .command = QString(button->text), .context = item->fullId(), .replyTo = { replyTo }, }); } break; case ButtonType::Callback: case ButtonType::Game: { SendBotCallbackData(controller, item, row, column); } break; case ButtonType::CallbackWithPassword: { SendBotCallbackDataWithPassword(controller, item, row, column); } break; case ButtonType::Buy: { Payments::CheckoutProcess::Start( item, Payments::Mode::Payment, crl::guard(controller, [=](auto) { controller->widget()->activate(); }), Payments::ProcessNonPanelPaymentFormFactory(controller, item)); } break; case ButtonType::Url: { auto url = QString::fromUtf8(button->data); auto skipConfirmation = false; if (const auto bot = item->getMessageBot()) { if (bot->isVerified()) { skipConfirmation = true; } } const auto variant = QVariant::fromValue(context); if (skipConfirmation) { UrlClickHandler::Open(url, variant); } else { HiddenUrlClickHandler::Open(url, variant); } } break; case ButtonType::RequestLocation: { HideSingleUseKeyboard(controller, item); controller->show( Ui::MakeInformBox(tr::lng_bot_share_location_unavailable())); } break; case ButtonType::RequestPhone: { HideSingleUseKeyboard(controller, item); const auto itemId = item->fullId(); const auto topicRootId = item->topicRootId(); const auto history = item->history(); controller->show(Ui::MakeConfirmBox({ .text = tr::lng_bot_share_phone(), .confirmed = [=] { controller->showPeerHistory( history, Window::SectionShow::Way::Forward, ShowAtTheEndMsgId); auto action = Api::SendAction(history); action.clearDraft = false; action.replyTo = { .messageId = itemId, .topicRootId = topicRootId, }; history->session().api().shareContact( history->session().user(), action); }, .confirmText = tr::lng_bot_share_phone_confirm(), })); } break; case ButtonType::RequestPoll: { HideSingleUseKeyboard(controller, item); auto chosen = kDefaultPollCreateFlags; auto disabled = PollData::Flags(); if (!button->data.isEmpty()) { disabled |= PollData::Flag::Quiz; if (button->data[0]) { chosen |= PollData::Flag::Quiz; } } const auto replyTo = FullReplyTo(); const auto suggest = SuggestOptions(); Window::PeerMenuCreatePoll( controller, item->history()->peer, replyTo, suggest, chosen, disabled); } break; case ButtonType::RequestPeer: { HideSingleUseKeyboard(controller, item); auto query = RequestPeerQuery(); Assert(button->data.size() == sizeof(query)); memcpy(&query, button->data.data(), sizeof(query)); const auto peer = item->history()->peer; const auto itemId = item->id; const auto id = int32(button->buttonId); const auto chosen = [=](std::vector> result) { using Flag = MTPmessages_SendBotRequestedPeer::Flag; peer->session().api().request(MTPmessages_SendBotRequestedPeer( MTP_flags(Flag::f_msg_id), peer->input(), MTP_int(itemId), MTPstring(), // request_id MTP_int(id), MTP_vector_from_range( result | ranges::views::transform([]( not_null peer) { return MTPInputPeer(peer->input()); })) )).done([=](const MTPUpdates &result) { peer->session().api().applyUpdates(result); }).send(); }; if (const auto bot = item->getMessageBot()) { ShowChoosePeerBox(controller, bot, query, chosen); } else { LOG(("API Error: Bot not found for RequestPeer button.")); } } break; case ButtonType::SwitchInlineSame: case ButtonType::SwitchInline: { if (const auto bot = item->getMessageBot()) { const auto fastSwitchDone = [&] { const auto samePeer = (button->type == ButtonType::SwitchInlineSame); if (samePeer) { SwitchInlineBotButtonReceived( controller, button->data, bot, item->id); return true; } else if (bot->isBot() && bot->botInfo->inlineReturnTo.key) { const auto switched = SwitchInlineBotButtonReceived( controller, button->data); if (switched) { return true; } } return false; }(); if (!fastSwitchDone) { const auto query = QString::fromUtf8(button->data); const auto chosen = [=](not_null thread) { return controller->switchInlineQuery( thread, bot, query); }; Window::ShowChooseRecipientBox( controller, chosen, tr::lng_inline_switch_choose(), nullptr, button->peerTypes); } } } break; case ButtonType::Auth: UrlAuthBox::ActivateButton(controller->uiShow(), item, row, column); break; case ButtonType::UserProfile: { const auto session = &item->history()->session(); const auto userId = UserId(button->data.toULongLong()); if (const auto user = session->data().userLoaded(userId)) { controller->showPeerInfo(user); } } break; case ButtonType::WebView: { if (const auto bot = item->getMessageBot()) { bot->session().attachWebView().open({ .bot = bot, .context = { .controller = controller }, .button = { .text = button->text, .url = button->data }, .source = InlineBots::WebViewSourceButton{ .simple = false }, }); } } break; case ButtonType::SimpleWebView: { if (const auto bot = item->getMessageBot()) { bot->session().attachWebView().open({ .bot = bot, .context = { .controller = controller }, .button = { .text = button->text, .url = button->data }, .source = InlineBots::WebViewSourceButton{ .simple = true }, }); } } break; case ButtonType::CopyText: { const auto text = QString::fromUtf8(button->data); if (!text.isEmpty()) { QGuiApplication::clipboard()->setText(text); controller->showToast(tr::lng_text_copied(tr::now)); } } break; case ButtonType::SuggestAccept: { Api::AcceptClickHandler(item)->onClick(ClickContext{ Qt::LeftButton, QVariant::fromValue(context), }); } break; case ButtonType::SuggestDecline: { Api::DeclineClickHandler(item)->onClick(ClickContext{ Qt::LeftButton, QVariant::fromValue(context), }); } break; case ButtonType::SuggestChange: { Api::SuggestChangesClickHandler(item)->onClick(ClickContext{ Qt::LeftButton, QVariant::fromValue(context), }); } break; case ButtonType::CreateBot: { HideSingleUseKeyboard(controller, item); auto suggestedName = QString(); auto suggestedUsername = QString(); { auto stream = QDataStream(button->data); stream >> suggestedName >> suggestedUsername; } const auto peer = item->history()->peer; const auto itemId = item->id; const auto id = int32(button->buttonId); const auto bot = item->getMessageBot(); if (!bot) { break; } ShowCreateManagedBotBox({ .show = controller->uiShow(), .manager = bot, .suggestedName = suggestedName, .suggestedUsername = suggestedUsername, .done = [=](not_null createdBot) { using Flag = MTPmessages_SendBotRequestedPeer::Flag; peer->session().api().request( MTPmessages_SendBotRequestedPeer( MTP_flags(Flag::f_msg_id), peer->input(), MTP_int(itemId), MTPstring(), MTP_int(id), MTP_vector( 1, createdBot->input())) ).done([=](const MTPUpdates &result) { peer->session().api().applyUpdates(result); }).send(); controller->showPeerHistory(createdBot); controller->showToast({ .title = tr::lng_managed_bot_created_title( tr::now, lt_name, createdBot->name()), .text = { tr::lng_managed_bot_created_text( tr::now, lt_parent_name, bot->name()) }, .icon = &st::toastCheckIcon, }); }, }); } break; } } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_bot.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once struct ClickHandlerContext; class HistoryItem; namespace Window { class SessionController; } // namespace Window namespace Api { void SendBotCallbackData( not_null controller, not_null item, int row, int column); void SendBotCallbackDataWithPassword( not_null controller, not_null item, int row, int column); bool SwitchInlineBotButtonReceived( not_null controller, const QByteArray &queryWithPeerTypes, UserData *samePeerBot = nullptr, MsgId samePeerReplyTo = 0); void ActivateBotCommand(ClickHandlerContext context, int row, int column); } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_filters.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_chat_filters.h" #include "api/api_text_entities.h" #include "apiwrap.h" #include "base/event_filter.h" #include "boxes/peer_list_box.h" #include "boxes/premium_limits_box.h" #include "boxes/filters/edit_filter_links.h" // FilterChatStatusText #include "core/application.h" #include "core/core_settings.h" #include "core/ui_integration.h" #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_chat_filters.h" #include "data/data_peer.h" #include "data/data_session.h" #include "history/history.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "ui/boxes/confirm_box.h" #include "ui/controls/filter_link_header.h" #include "ui/text/text_utilities.h" #include "ui/toast/toast.h" #include "ui/widgets/buttons.h" #include "ui/filter_icons.h" #include "ui/vertical_list.h" #include "ui/ui_utility.h" #include "window/window_session_controller.h" #include "styles/style_filter_icons.h" #include "styles/style_layers.h" #include "styles/style_settings.h" namespace Api { namespace { enum class ToggleAction { Adding, Removing, }; class ToggleChatsController final : public PeerListController , public base::has_weak_ptr { public: ToggleChatsController( not_null window, ToggleAction action, Data::ChatFilterTitle title, std::vector> chats, std::vector> additional); void prepare() override; void rowClicked(not_null row) override; Main::Session &session() const override; [[nodiscard]] auto selectedValue() const -> rpl::producer>>; void adjust(int minHeight, int maxHeight, int addedTopHeight); void setRealContentHeight(rpl::producer value); rpl::producer boxHeightValue() const override; private: void setupAboveWidget(); void setupBelowWidget(); void initDesiredHeightValue(); void toggleAllSelected(bool select); const not_null _window; Ui::RpWidget *_addedTopWidget = nullptr; Ui::RpWidget *_addedBottomWidget = nullptr; ToggleAction _action = ToggleAction::Adding; base::flat_set> _checkable; std::vector> _chats; std::vector> _additional; rpl::variable>> _selected; int _minTopHeight = 0; rpl::variable _maxTopHeight; rpl::variable _aboveHeight; rpl::variable _belowHeight; rpl::variable _desiredHeight; base::unique_qptr _menu; rpl::lifetime _lifetime; }; [[nodiscard]] tr::phrase<> TitleText(Ui::FilterLinkHeaderType type) { using Type = Ui::FilterLinkHeaderType; switch (type) { case Type::AddingFilter: return tr::lng_filters_by_link_title; case Type::AddingChats: return tr::lng_filters_by_link_more; case Type::AllAdded: return tr::lng_filters_by_link_already; case Type::Removing: return tr::lng_filters_by_link_remove; } Unexpected("Ui::FilterLinkHeaderType in TitleText."); } [[nodiscard]] TextWithEntities AboutText( Ui::FilterLinkHeaderType type, TextWithEntities title) { using Type = Ui::FilterLinkHeaderType; auto boldTitle = Ui::Text::Wrapped(title, EntityType::Bold); return (type == Type::AddingFilter) ? tr::lng_filters_by_link_sure( tr::now, lt_folder, std::move(boldTitle), tr::marked) : (type == Type::AddingChats) ? tr::lng_filters_by_link_more_sure( tr::now, lt_folder, std::move(boldTitle), tr::marked) : (type == Type::AllAdded) ? tr::lng_filters_by_link_already_about( tr::now, lt_folder, std::move(boldTitle), tr::marked) : tr::lng_filters_by_link_remove_sure( tr::now, lt_folder, std::move(boldTitle), tr::marked); } void InitFilterLinkHeader( not_null box, Fn adjust, Ui::FilterLinkHeaderType type, Data::ChatFilterTitle title, QString iconEmoji, rpl::producer count, bool horizontalFilters) { const auto icon = Ui::LookupFilterIcon( Ui::LookupFilterIconByEmoji( iconEmoji ).value_or(Ui::FilterIcon::Custom)).active; const auto isStatic = title.isStatic; auto header = Ui::MakeFilterLinkHeader(box, { .type = type, .title = TitleText(type)(tr::now), .about = AboutText(type, title.text), .aboutContext = Core::TextContext({ .session = &box->peerListUiShow()->session(), .customEmojiLoopLimit = isStatic ? -1 : 0, }), .folderTitle = title.text, .folderIcon = icon, .badge = (type == Ui::FilterLinkHeaderType::AddingChats ? std::move(count) : rpl::single(0)), .horizontalFilters = horizontalFilters, }); const auto widget = header.widget; widget->resizeToWidth(st::boxWideWidth); Ui::SendPendingMoveResizeEvents(widget); const auto min = widget->minimumHeight(), max = widget->maximumHeight(); widget->resize(st::boxWideWidth, max); box->setAddedTopScrollSkip(max); std::move( header.wheelEvents ) | rpl::on_next([=](not_null e) { box->sendScrollViewportEvent(e); }, widget->lifetime()); std::move( header.closeRequests ) | rpl::on_next([=] { box->closeBox(); }, widget->lifetime()); struct State { bool processing = false; int addedTopHeight = 0; }; const auto state = widget->lifetime().make_state(); box->scrolls( ) | rpl::filter([=] { return !state->processing; }) | rpl::on_next([=] { state->processing = true; const auto guard = gsl::finally([&] { state->processing = false; }); const auto top = box->scrollTop(); const auto headerHeight = std::max(max - top, min); const auto addedTopHeight = max - headerHeight; widget->resize(widget->width(), headerHeight); if (state->addedTopHeight < addedTopHeight) { adjust(min, max, addedTopHeight); box->setAddedTopScrollSkip(headerHeight); } else { box->setAddedTopScrollSkip(headerHeight); adjust(min, max, addedTopHeight); } state->addedTopHeight = addedTopHeight; box->peerListRefreshRows(); }, widget->lifetime()); box->setNoContentMargin(true); adjust(min, max, 0); } void ImportInvite( const QString &slug, FilterId filterId, const base::flat_set> &peers, Fn done, Fn fail) { Expects(!peers.empty()); const auto peer = peers.front(); const auto api = &peer->session().api(); const auto callback = [=](const MTPUpdates &result) { api->applyUpdates(result); if (slug.isEmpty()) { peer->owner().chatsFilters().moreChatsHide(filterId, true); } done(); }; const auto error = [=](const MTP::Error &error) { fail(error.type()); }; auto inputs = peers | ranges::views::transform([](auto peer) { return MTPInputPeer(peer->input()); }) | ranges::to>(); if (!slug.isEmpty()) { api->request(MTPchatlists_JoinChatlistInvite( MTP_string(slug), MTP_vector(std::move(inputs)) )).done(callback).fail(error).handleFloodErrors().send(); } else { api->request(MTPchatlists_JoinChatlistUpdates( MTP_inputChatlistDialogFilter(MTP_int(filterId)), MTP_vector(std::move(inputs)) )).done(callback).fail(error).handleFloodErrors().send(); } } ToggleChatsController::ToggleChatsController( not_null window, ToggleAction action, Data::ChatFilterTitle title, std::vector> chats, std::vector> additional) : _window(window) , _action(action) , _chats(std::move(chats)) , _additional(std::move(additional)) { setStyleOverrides(&st::filterLinkChatsList); } void ToggleChatsController::prepare() { auto selected = base::flat_set>(); const auto disabled = [](not_null peer) { return peer->isChat() ? peer->asChat()->isForbidden() : peer->isChannel() ? peer->asChannel()->isForbidden() : false; }; const auto add = [&](not_null peer, bool additional = false) { const auto disable = disabled(peer); auto row = (additional || !disable) ? std::make_unique(peer) : MakeFilterChatRow( peer, tr::lng_filters_link_inaccessible(tr::now), true); if (delegate()->peerListFindRow(peer->id.value)) { return; } const auto raw = row.get(); delegate()->peerListAppendRow(std::move(row)); if (!disable && (!additional || _action == ToggleAction::Removing)) { _checkable.emplace(peer); if (const auto status = FilterChatStatusText(peer) ; !status.isEmpty()) { raw->setCustomStatus(status); } } if (disable) { } else if (!additional) { delegate()->peerListSetRowChecked(raw, true); raw->finishCheckedAnimation(); selected.emplace(peer); } else if (_action == ToggleAction::Adding) { raw->setDisabledState(PeerListRow::State::DisabledChecked); raw->setCustomStatus(peer->isBroadcast() ? tr::lng_filters_link_already_channel(tr::now) : tr::lng_filters_link_already_group(tr::now)); } }; for (const auto &peer : _chats) { if (!disabled(peer)) { add(peer); } } for (const auto &peer : _additional) { add(peer, true); } for (const auto &peer : _chats) { if (disabled(peer)) { add(peer); } } setupAboveWidget(); setupBelowWidget(); initDesiredHeightValue(); delegate()->peerListRefreshRows(); _selected = std::move(selected); } void ToggleChatsController::rowClicked(not_null row) { const auto peer = row->peer(); if (!_checkable.contains(peer)) { return; } const auto checked = row->checked(); auto selected = _selected.current(); delegate()->peerListSetRowChecked(row, !checked); if (checked) { selected.remove(peer); } else { selected.emplace(peer); } _selected = std::move(selected); } void ToggleChatsController::setupAboveWidget() { using namespace Settings; auto wrap = object_ptr((QWidget*)nullptr); const auto container = wrap.data(); _addedTopWidget = container->add(object_ptr(container)); const auto realAbove = container->add( object_ptr(container)); Ui::AddDivider(realAbove); const auto totalCount = [&] { if (_chats.empty()) { return _additional.size(); } else if (_additional.empty()) { return _chats.size(); } auto result = _chats.size(); for (const auto &peer : _additional) { if (!ranges::contains(_chats, peer)) { ++result; } } return result; }; const auto count = (_action == ToggleAction::Removing) ? totalCount() : _chats.empty() ? _additional.size() : _chats.size(); const auto selectableCount = int(_checkable.size()); auto selectedCount = _selected.value( ) | rpl::map([](const base::flat_set> &selected) { return int(selected.size()); }); AddFilterSubtitleWithToggles( realAbove, (_action == ToggleAction::Removing ? tr::lng_filters_by_link_quit : _chats.empty() ? tr::lng_filters_by_link_in : tr::lng_filters_by_link_join)( lt_count, rpl::single(float64(count))), selectableCount, std::move(selectedCount), [=](bool select) { toggleAllSelected(select); }); _aboveHeight = realAbove->heightValue(); delegate()->peerListSetAboveWidget(std::move(wrap)); } void ToggleChatsController::toggleAllSelected(bool select) { auto selected = _selected.current(); if (!select) { if (selected.empty()) { return; } for (const auto &peer : selected) { const auto row = delegate()->peerListFindRow(peer->id.value); Assert(row != nullptr); delegate()->peerListSetRowChecked(row, false); } selected = {}; } else { const auto count = delegate()->peerListFullRowsCount(); for (auto i = 0; i != count; ++i) { const auto row = delegate()->peerListRowAt(i); const auto peer = row->peer(); if (_action != ToggleAction::Adding || !ranges::contains(_additional, peer)) { delegate()->peerListSetRowChecked(row, true); selected.emplace(peer); } } } _selected = std::move(selected); } void ToggleChatsController::setupBelowWidget() { if (_chats.empty()) { auto widget = object_ptr((QWidget*)nullptr); _addedBottomWidget = widget.data(); delegate()->peerListSetBelowWidget(std::move(widget)); return; } auto layout = object_ptr((QWidget*)nullptr); const auto raw = layout.data(); auto widget = object_ptr( (QWidget*)nullptr, std::move(layout), st::defaultBoxDividerLabelPadding); raw->add(object_ptr( raw, (_action == ToggleAction::Removing ? tr::lng_filters_by_link_about_quit : tr::lng_filters_by_link_about)(tr::now), st::boxDividerLabel)); _addedBottomWidget = raw->add(object_ptr(raw)); _belowHeight = widget->heightValue() | rpl::map([=](int value) { return value - _addedBottomWidget->height(); }); delegate()->peerListSetBelowWidget(std::move(widget)); } Main::Session &ToggleChatsController::session() const { return _window->session(); } auto ToggleChatsController::selectedValue() const -> rpl::producer>> { return _selected.value(); } void ToggleChatsController::adjust( int minHeight, int maxHeight, int addedTopHeight) { Expects(addedTopHeight >= 0); _addedTopWidget->resize(_addedTopWidget->width(), addedTopHeight); _minTopHeight = minHeight; _maxTopHeight = maxHeight; } void ToggleChatsController::setRealContentHeight(rpl::producer value) { std::move( value ) | rpl::on_next([=](int height) { const auto desired = _desiredHeight.current(); if (height <= computeListSt().item.height) { return; } else if (height >= desired) { _addedBottomWidget->resize(_addedBottomWidget->width(), 0); } else { const auto available = desired - height; const auto required = _maxTopHeight.current() - _minTopHeight; const auto added = required - available; _addedBottomWidget->resize( _addedBottomWidget->width(), std::max(added, 0)); } }, _lifetime); } void ToggleChatsController::initDesiredHeightValue() { using namespace rpl::mappers; const auto &st = computeListSt(); const auto count = int(delegate()->peerListFullRowsCount()); const auto middle = st.padding.top() + (count * st.item.height) + st.padding.bottom(); _desiredHeight = rpl::combine( _maxTopHeight.value(), _aboveHeight.value(), _belowHeight.value(), _1 + _2 + middle + _3); } rpl::producer ToggleChatsController::boxHeightValue() const { return _desiredHeight.value() | rpl::map([=](int value) { return std::min(value, st::boxMaxListHeight); }); } void ShowImportError( not_null window, FilterId id, int added, const QString &error) { const auto session = &window->session(); const auto &list = session->data().chatsFilters().list(); const auto i = ranges::find(list, id, &Data::ChatFilter::id); const auto count = added + ((i != end(list)) ? int(i->always().size()) : 0); if (error == u"CHANNELS_TOO_MUCH"_q) { window->show(Box(ChannelsLimitBox, session)); } else if (error == u"FILTER_INCLUDE_TOO_MUCH"_q) { window->show(Box(FilterChatsLimitBox, session, count, true)); } else if (error == u"CHATLISTS_TOO_MUCH"_q) { window->show(Box(ShareableFiltersLimitBox, session)); } else { window->showToast((error == u"INVITE_SLUG_EXPIRED"_q) ? tr::lng_group_invite_bad_link(tr::now) : error.startsWith(u"FLOOD_WAIT_"_q) ? tr::lng_flood_error(tr::now) : error); } } void ShowImportToast( base::weak_ptr weak, Data::ChatFilterTitle title, Ui::FilterLinkHeaderType type, int added) { const auto strong = weak.get(); if (!strong) { return; } const auto created = (type == Ui::FilterLinkHeaderType::AddingFilter); const auto phrase = created ? tr::lng_filters_added_title : tr::lng_filters_updated_title; auto text = Ui::Text::Wrapped( phrase(tr::now, lt_folder, title.text, tr::marked), EntityType::Bold); if (added > 0) { const auto phrase = created ? tr::lng_filters_added_also : tr::lng_filters_updated_also; text.append('\n').append(phrase(tr::now, lt_count, added)); } const auto isStatic = title.isStatic; strong->showToast({ .text = std::move(text), .textContext = Core::TextContext({ .session = &strong->session(), .customEmojiLoopLimit = isStatic ? -1 : 0, }) }); } void HandleEnterInBox(not_null box) { const auto isEnter = [=](not_null event) { if (event->type() == QEvent::KeyPress) { if (const auto k = static_cast(event.get())) { return (k->key() == Qt::Key_Enter) || (k->key() == Qt::Key_Return); } } return false; }; base::install_event_filter(box, [=](not_null event) { if (isEnter(event)) { box->triggerButton(0); return base::EventFilterResult::Cancel; } return base::EventFilterResult::Continue; }); } void ProcessFilterInvite( base::weak_ptr weak, const QString &slug, FilterId filterId, Data::ChatFilterTitle title, QString iconEmoji, std::vector> peers, std::vector> already) { const auto strong = weak.get(); if (!strong) { return; } Core::App().hideMediaView(); if (peers.empty() && !filterId) { strong->showToast(tr::lng_group_invite_bad_link(tr::now)); return; } const auto fullyAdded = (peers.empty() && filterId); auto controller = std::make_unique( strong, ToggleAction::Adding, title, std::move(peers), std::move(already)); const auto horizontalFilters = !strong->enoughSpaceForFilters() || Core::App().settings().chatFiltersHorizontal(); const auto raw = controller.get(); auto initBox = [=](not_null box) { box->setStyle(st::filterInviteBox); using Type = Ui::FilterLinkHeaderType; const auto type = fullyAdded ? Type::AllAdded : !filterId ? Type::AddingFilter : Type::AddingChats; auto badge = raw->selectedValue( ) | rpl::map([=](const base::flat_set> &peers) { return int(peers.size()); }); InitFilterLinkHeader(box, [=](int min, int max, int addedTop) { raw->adjust(min, max, addedTop); }, type, title, iconEmoji, rpl::duplicate(badge), horizontalFilters); raw->setRealContentHeight(box->heightValue()); const auto isStatic = title.isStatic; auto owned = Ui::FilterLinkProcessButton( box, type, title.text, Core::TextContext({ .session = &strong->session(), .customEmojiLoopLimit = isStatic ? -1 : 0, }), std::move(badge)); const auto button = owned.data(); box->widthValue( ) | rpl::on_next([=](int width) { const auto &padding = st::filterInviteBox.buttonPadding; button->resizeToWidth(width - padding.left() - padding.right()); button->moveToLeft(padding.left(), padding.top()); }, button->lifetime()); box->addButton(std::move(owned)); HandleEnterInBox(box); struct State { bool importing = false; }; const auto state = box->lifetime().make_state(); raw->selectedValue( ) | rpl::on_next([=]( base::flat_set> &&peers) { button->setClickedCallback([=] { if (peers.empty()) { box->closeBox(); } else if (!state->importing) { state->importing = true; const auto added = int(peers.size()); ImportInvite(slug, filterId, peers, crl::guard(box, [=] { ShowImportToast(weak, title, type, peers.size()); box->closeBox(); }), crl::guard(box, [=](QString text) { if (const auto strong = weak.get()) { ShowImportError(strong, filterId, added, text); } state->importing = false; })); } }); }, box->lifetime()); }; strong->show( Box(std::move(controller), std::move(initBox))); } void ProcessFilterInvite( base::weak_ptr weak, const QString &slug, FilterId filterId, std::vector> peers, std::vector> already) { const auto strong = weak.get(); if (!strong) { return; } Core::App().hideMediaView(); const auto &list = strong->session().data().chatsFilters().list(); const auto it = ranges::find(list, filterId, &Data::ChatFilter::id); if (it == end(list)) { strong->showToast(u"Filter not found :shrug:"_q); return; } ProcessFilterInvite( weak, slug, filterId, it->title(), it->iconEmoji(), std::move(peers), std::move(already)); } } // namespace void SaveNewFilterPinned( not_null session, FilterId filterId) { const auto &order = session->data().pinnedChatsOrder(filterId); auto &filters = session->data().chatsFilters(); const auto &filter = filters.applyUpdatedPinned(filterId, order); session->api().request(MTPmessages_UpdateDialogFilter( MTP_flags(MTPmessages_UpdateDialogFilter::Flag::f_filter), MTP_int(filterId), filter.tl() )).send(); } void CheckFilterInvite( not_null controller, const QString &slug) { const auto session = &controller->session(); const auto weak = base::make_weak(controller); session->api().checkFilterInvite(slug, [=]( const MTPchatlists_ChatlistInvite &result) { const auto strong = weak.get(); if (!strong) { return; } auto title = Data::ChatFilterTitle(); auto iconEmoji = QString(); auto filterId = FilterId(); auto peers = std::vector>(); auto already = std::vector>(); auto &owner = strong->session().data(); result.match([&](const auto &data) { owner.processUsers(data.vusers()); owner.processChats(data.vchats()); }); const auto parseList = [&](const MTPVector &list) { auto result = std::vector>(); result.reserve(list.v.size()); for (const auto &peer : list.v) { result.push_back(owner.peer(peerFromMTP(peer))); } return result; }; result.match([&](const MTPDchatlists_chatlistInvite &data) { title.text = ParseTextWithEntities(session, data.vtitle()); title.isStatic = data.is_title_noanimate(); iconEmoji = data.vemoticon().value_or_empty(); peers = parseList(data.vpeers()); }, [&](const MTPDchatlists_chatlistInviteAlready &data) { filterId = data.vfilter_id().v; peers = parseList(data.vmissing_peers()); already = parseList(data.valready_peers()); }); const auto notLoaded = filterId && !ranges::contains( owner.chatsFilters().list(), filterId, &Data::ChatFilter::id); if (notLoaded) { const auto lifetime = std::make_shared(); owner.chatsFilters().changed( ) | rpl::on_next([=] { lifetime->destroy(); ProcessFilterInvite( weak, slug, filterId, std::move(peers), std::move(already)); }, *lifetime); owner.chatsFilters().reload(); } else if (filterId) { ProcessFilterInvite( weak, slug, filterId, std::move(peers), std::move(already)); } else { ProcessFilterInvite( weak, slug, filterId, title, iconEmoji, std::move(peers), std::move(already)); } }, [=](const MTP::Error &error) { if (error.code() != 400) { return; } ProcessFilterInvite(weak, slug, {}, {}, {}, {}, {}); }); } void ProcessFilterUpdate( base::weak_ptr weak, FilterId filterId, std::vector> missing) { if (const auto strong = missing.empty() ? weak.get() : nullptr) { strong->session().data().chatsFilters().moreChatsHide(filterId); return; } ProcessFilterInvite(weak, QString(), filterId, std::move(missing), {}); } void ProcessFilterRemove( base::weak_ptr weak, Data::ChatFilterTitle title, QString iconEmoji, std::vector> all, std::vector> suggest, Fn>)> done) { const auto strong = weak.get(); if (!strong) { return; } Core::App().hideMediaView(); if (all.empty() && suggest.empty()) { done({}); return; } auto controller = std::make_unique( strong, ToggleAction::Removing, title, std::move(suggest), std::move(all)); const auto horizontalFilters = !strong->enoughSpaceForFilters() || Core::App().settings().chatFiltersHorizontal(); const auto raw = controller.get(); auto initBox = [=](not_null box) { box->setStyle(st::filterInviteBox); const auto type = Ui::FilterLinkHeaderType::Removing; auto badge = raw->selectedValue( ) | rpl::map([=](const base::flat_set> &peers) { return int(peers.size()); }); InitFilterLinkHeader(box, [=](int min, int max, int addedTop) { raw->adjust(min, max, addedTop); }, type, title, iconEmoji, rpl::single(0), horizontalFilters); const auto isStatic = title.isStatic; auto owned = Ui::FilterLinkProcessButton( box, type, title.text, Core::TextContext({ .session = &strong->session(), .customEmojiLoopLimit = isStatic ? -1 : 0, }), std::move(badge)); const auto button = owned.data(); box->widthValue( ) | rpl::on_next([=](int width) { const auto &padding = st::filterInviteBox.buttonPadding; button->resizeToWidth(width - padding.left() - padding.right()); button->moveToLeft(padding.left(), padding.top()); }, button->lifetime()); box->addButton(std::move(owned)); HandleEnterInBox(box); raw->selectedValue( ) | rpl::on_next([=]( base::flat_set> &&peers) { button->setClickedCallback([=] { done(peers | ranges::to_vector); box->closeBox(); }); }, box->lifetime()); }; strong->show( Box(std::move(controller), std::move(initBox))); } [[nodiscard]] std::vector> ExtractSuggestRemoving( const Data::ChatFilter &filter) { if (!filter.chatlist()) { return {}; } return filter.always() | ranges::views::filter([]( not_null history) { return history->peer->isChannel(); }) | ranges::views::transform(&History::peer) | ranges::to_vector; } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_filters.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once namespace Main { class Session; } // namespace Main namespace Window { class SessionController; } // namespace Window namespace Data { class ChatFilter; struct ChatFilterTitle; } // namespace Data namespace Api { void SaveNewFilterPinned( not_null session, FilterId filterId); void CheckFilterInvite( not_null controller, const QString &slug); void ProcessFilterUpdate( base::weak_ptr weak, FilterId filterId, std::vector> missing); void ProcessFilterRemove( base::weak_ptr weak, Data::ChatFilterTitle title, QString iconEmoji, std::vector> all, std::vector> suggest, Fn>)> done); [[nodiscard]] std::vector> ExtractSuggestRemoving( const Data::ChatFilter &filter); } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_filters_remove_manager.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_chat_filters_remove_manager.h" #include "api/api_chat_filters.h" #include "apiwrap.h" #include "data/data_chat_filters.h" #include "data/data_peer.h" #include "data/data_session.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "ui/boxes/confirm_box.h" #include "ui/ui_utility.h" #include "window/window_controller.h" #include "window/window_session_controller.h" #include "styles/style_layers.h" namespace Api { namespace { void RemoveChatFilter( not_null session, FilterId filterId, std::vector> leave) { const auto api = &session->api(); session->data().chatsFilters().apply(MTP_updateDialogFilter( MTP_flags(MTPDupdateDialogFilter::Flag(0)), MTP_int(filterId), MTPDialogFilter())); if (leave.empty()) { api->request(MTPmessages_UpdateDialogFilter( MTP_flags(MTPmessages_UpdateDialogFilter::Flag(0)), MTP_int(filterId), MTPDialogFilter() )).send(); } else { api->request(MTPchatlists_LeaveChatlist( MTP_inputChatlistDialogFilter(MTP_int(filterId)), MTP_vector(ranges::views::all( leave ) | ranges::views::transform([](not_null peer) { return MTPInputPeer(peer->input()); }) | ranges::to>()) )).done([=](const MTPUpdates &result) { api->applyUpdates(result); }).send(); } } } // namespace RemoveComplexChatFilter::RemoveComplexChatFilter() = default; void RemoveComplexChatFilter::request( base::weak_qptr widget, base::weak_ptr weak, FilterId id) { const auto session = &weak->session(); const auto &list = session->data().chatsFilters().list(); const auto i = ranges::find(list, id, &Data::ChatFilter::id); const auto filter = (i != end(list)) ? *i : Data::ChatFilter(); const auto has = filter.hasMyLinks(); const auto confirm = [=](Fn action, bool onlyWhenHas = false) { if (!has && onlyWhenHas) { action(); return; } weak->window().show(Ui::MakeConfirmBox({ .text = (has ? tr::lng_filters_delete_sure() : tr::lng_filters_remove_sure()), .confirmed = [=](Fn &&close) { close(); action(); }, .confirmText = (has ? tr::lng_box_delete() : tr::lng_filters_remove_yes()), .confirmStyle = &st::attentionBoxButton, })); }; const auto simple = [=] { confirm([=] { RemoveChatFilter(session, id, {}); }); }; const auto suggestRemoving = Api::ExtractSuggestRemoving(filter); if (suggestRemoving.empty()) { simple(); return; } else if (_removingRequestId) { if (_removingId == id) { return; } session->api().request(_removingRequestId).cancel(); } _removingId = id; _removingRequestId = session->api().request( MTPchatlists_GetLeaveChatlistSuggestions( MTP_inputChatlistDialogFilter( MTP_int(id))) ).done(crl::guard(widget, [=, this](const MTPVector &result) { _removingRequestId = 0; const auto suggestRemovePeers = ranges::views::all( result.v ) | ranges::views::transform([=](const MTPPeer &peer) { return session->data().peer(peerFromMTP(peer)); }) | ranges::to_vector; const auto chosen = crl::guard(widget, [=]( std::vector> peers) { RemoveChatFilter(session, id, std::move(peers)); }); confirm(crl::guard(widget, [=] { Api::ProcessFilterRemove( weak, filter.title(), filter.iconEmoji(), suggestRemoving, suggestRemovePeers, chosen); }), true); })).fail(crl::guard(widget, [=, this] { _removingRequestId = 0; simple(); })).send(); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_filters_remove_manager.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once namespace Window { class SessionController; } // namespace Window namespace Ui { class RpWidget; } // namespace Ui namespace Api { class RemoveComplexChatFilter final { public: RemoveComplexChatFilter(); void request( base::weak_qptr widget, base::weak_ptr weak, FilterId id); private: FilterId _removingId = 0; mtpRequestId _removingRequestId = 0; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_invite.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_chat_invite.h" #include "apiwrap.h" #include "api/api_credits.h" #include "boxes/premium_limits_box.h" #include "core/application.h" #include "data/components/credits.h" #include "data/data_channel.h" #include "data/data_file_origin.h" #include "data/data_forum.h" #include "data/data_photo.h" #include "data/data_photo_media.h" #include "data/data_session.h" #include "data/data_user.h" #include "info/channel_statistics/boosts/giveaway/boost_badge.h" #include "info/profile/info_profile_badge.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "settings/settings_credits_graphics.h" #include "ui/boxes/confirm_box.h" #include "ui/controls/userpic_button.h" #include "ui/effects/credits_graphics.h" #include "ui/effects/premium_graphics.h" #include "ui/effects/premium_stars_colored.h" #include "ui/empty_userpic.h" #include "ui/layers/generic_box.h" #include "ui/painter.h" #include "ui/rect.h" #include "ui/text/text_utilities.h" #include "ui/toast/toast.h" #include "ui/vertical_list.h" #include "window/window_session_controller.h" #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" #include "styles/style_credits.h" #include "styles/style_info.h" #include "styles/style_layers.h" #include "styles/style_premium.h" namespace Api { namespace { struct InviteParticipant { not_null user; Ui::PeerUserpicView userpic; }; struct ChatInvite { QString title; QString about; PhotoData *photo = nullptr; int participantsCount = 0; std::vector participants; bool isPublic = false; bool isChannel = false; bool isMegagroup = false; bool isBroadcast = false; bool isRequestNeeded = false; bool isFake = false; bool isScam = false; bool isVerified = false; }; [[nodiscard]] ChatInvite ParseInvite( not_null session, const MTPDchatInvite &data) { auto participants = std::vector(); if (const auto list = data.vparticipants()) { participants.reserve(list->v.size()); for (const auto &participant : list->v) { if (const auto user = session->data().processUser(participant)) { participants.push_back(InviteParticipant{ user }); } } } const auto photo = session->data().processPhoto(data.vphoto()); return { .title = qs(data.vtitle()), .about = data.vabout().value_or_empty(), .photo = (photo->isNull() ? nullptr : photo.get()), .participantsCount = data.vparticipants_count().v, .participants = std::move(participants), .isPublic = data.is_public(), .isChannel = data.is_channel(), .isMegagroup = data.is_megagroup(), .isBroadcast = data.is_broadcast(), .isRequestNeeded = data.is_request_needed(), .isFake = data.is_fake(), .isScam = data.is_scam(), .isVerified = data.is_verified(), }; } [[nodiscard]] Info::Profile::BadgeType BadgeForInvite( const ChatInvite &invite) { using Type = Info::Profile::BadgeType; return invite.isVerified ? Type::Verified : invite.isScam ? Type::Scam : invite.isFake ? Type::Fake : Type::None; } void SubmitChatInvite( base::weak_ptr weak, not_null session, const QString &hash, bool isGroup) { session->api().request(MTPmessages_ImportChatInvite( MTP_string(hash) )).done([=](const MTPUpdates &result) { session->api().applyUpdates(result); const auto strongController = weak.get(); if (!strongController) { return; } strongController->hideLayer(); const auto handleChats = [&](const MTPVector &chats) { if (chats.v.isEmpty()) { return; } const auto peerId = chats.v[0].match([](const MTPDchat &data) { return peerFromChat(data.vid().v); }, [](const MTPDchannel &data) { return peerFromChannel(data.vid().v); }, [](auto&&) { return PeerId(0); }); if (const auto peer = session->data().peerLoaded(peerId)) { // Shows in the primary window anyway. strongController->showPeerHistory( peer, Window::SectionShow::Way::Forward); } }; result.match([&](const MTPDupdates &data) { handleChats(data.vchats()); }, [&](const MTPDupdatesCombined &data) { handleChats(data.vchats()); }, [&](auto &&) { LOG(("API Error: unexpected update cons %1 " "(ApiWrap::importChatInvite)").arg(result.type())); }); }).fail([=](const MTP::Error &error) { const auto &type = error.type(); const auto strongController = weak.get(); if (!strongController) { return; } else if (type == u"CHANNELS_TOO_MUCH"_q) { strongController->show( Box(ChannelsLimitBox, &strongController->session())); return; } strongController->hideLayer(); strongController->showToast([&] { if (type == u"INVITE_REQUEST_SENT"_q) { return isGroup ? tr::lng_group_request_sent(tr::now) : tr::lng_group_request_sent_channel(tr::now); } else if (type == u"USERS_TOO_MUCH"_q) { return tr::lng_group_invite_no_room(tr::now); } else { return tr::lng_group_invite_bad_link(tr::now); } }(), ApiWrap::kJoinErrorDuration); }).send(); } void ConfirmSubscriptionBox( not_null box, not_null session, const QString &hash, const MTPDchatInvite *data) { box->setWidth(st::boxWideWidth); const auto amount = data->vsubscription_pricing()->data().vamount().v; const auto formId = data->vsubscription_form_id()->v; const auto name = qs(data->vtitle()); const auto maybePhoto = session->data().processPhoto(data->vphoto()); const auto photo = maybePhoto->isNull() ? nullptr : maybePhoto.get(); struct State final { std::shared_ptr photoMedia; std::unique_ptr photoEmpty; QImage frame; std::optional api; Ui::RpWidget* saveButton = nullptr; rpl::variable loading; }; const auto state = box->lifetime().make_state(); const auto content = box->verticalLayout(); Ui::AddSkip(content, st::confirmInvitePhotoTop); const auto userpic = content->add( object_ptr(content), style::al_top); const auto photoSize = st::confirmInvitePhotoSize; userpic->resize(Size(photoSize)); userpic->setNaturalWidth(photoSize); const auto creditsIconSize = photoSize / 3; const auto creditsIconCallback = Ui::PaintOutlinedColoredCreditsIconCallback( creditsIconSize, 1.5); state->frame = QImage( Size(photoSize * style::DevicePixelRatio()), QImage::Format_ARGB32_Premultiplied); state->frame.setDevicePixelRatio(style::DevicePixelRatio()); const auto options = Images::Option::RoundCircle; userpic->paintRequest( ) | rpl::on_next([=, small = Data::PhotoSize::Small] { state->frame.fill(Qt::transparent); { auto p = QPainter(&state->frame); if (state->photoMedia) { if (const auto image = state->photoMedia->image(small)) { p.drawPixmap( 0, 0, image->pix(Size(photoSize), { .options = options })); } } else if (state->photoEmpty) { state->photoEmpty->paintCircle( p, 0, 0, userpic->width(), photoSize); } if (creditsIconCallback) { p.translate( photoSize - creditsIconSize, photoSize - creditsIconSize); creditsIconCallback(p); } } auto p = QPainter(userpic); p.drawImage(0, 0, state->frame); }, userpic->lifetime()); userpic->setAttribute(Qt::WA_TransparentForMouseEvents); if (photo) { state->photoMedia = photo->createMediaView(); state->photoMedia->wanted(Data::PhotoSize::Small, Data::FileOrigin()); if (!state->photoMedia->image(Data::PhotoSize::Small)) { session->downloaderTaskFinished( ) | rpl::on_next([=] { userpic->update(); }, userpic->lifetime()); } } else { state->photoEmpty = std::make_unique( Ui::EmptyUserpic::UserpicColor(0), name); } Ui::AddSkip(content); Ui::AddSkip(content); Settings::AddMiniStars( content, Ui::CreateChild(content), photoSize, box->width(), 2.); box->addRow( object_ptr( box, tr::lng_channel_invite_subscription_title(), st::inviteLinkSubscribeBoxTitle), style::al_top); box->addRow( object_ptr( box, tr::lng_channel_invite_subscription_about( lt_channel, rpl::single(tr::bold(name)), lt_price, tr::lng_credits_summary_options_credits( lt_count, rpl::single(amount) | tr::to_count(), tr::bold), tr::marked), st::inviteLinkSubscribeBoxAbout), style::al_top); Ui::AddSkip(content); box->addRow( object_ptr( box, tr::lng_channel_invite_subscription_terms( lt_link, rpl::combine( tr::lng_paid_react_agree_link(), tr::lng_group_invite_subscription_about_url() ) | rpl::map([](const QString &text, const QString &url) { return tr::link(text, url); }), tr::rich), st::inviteLinkSubscribeBoxTerms), style::al_top); { const auto balance = Settings::AddBalanceWidget( content, session, session->credits().balanceValue(), true); session->credits().load(true); rpl::combine( balance->sizeValue(), content->sizeValue() ) | rpl::on_next([=](const QSize &, const QSize &) { balance->moveToRight( st::creditsHistoryRightSkip * 2, st::creditsHistoryRightSkip); balance->update(); }, balance->lifetime()); } const auto sendCredits = [=, weak = base::make_weak(box)] { const auto show = box->uiShow(); const auto buttonWidth = state->saveButton ? state->saveButton->width() : 0; const auto finish = [=] { state->api = std::nullopt; state->loading.force_assign(false); if (const auto strong = weak.get()) { strong->closeBox(); } }; state->api->request( MTPpayments_SendStarsForm( MTP_long(formId), MTP_inputInvoiceChatInviteSubscription(MTP_string(hash))) ).done([=](const MTPpayments_PaymentResult &result) { result.match([&](const MTPDpayments_paymentResult &data) { session->api().applyUpdates(data.vupdates()); }, [](const MTPDpayments_paymentVerificationNeeded &data) { }); const auto refill = session->data().activeCreditsSubsRebuilder(); const auto strong = weak.get(); if (!strong) { return; } if (!refill) { return finish(); } const auto api = strong->lifetime().make_state( session->user(), true, true); api->requestSubscriptions({}, [=](Data::CreditsStatusSlice d) { refill->fire(std::move(d)); finish(); }); }).fail([=](const MTP::Error &error) { const auto id = error.type(); if (weak) { state->api = std::nullopt; } show->showToast(id); state->loading.force_assign(false); }).send(); if (state->saveButton) { state->saveButton->resizeToWidth(buttonWidth); } }; auto confirmText = tr::lng_channel_invite_subscription_button(); state->saveButton = box->addButton(std::move(confirmText), [=] { if (state->api) { return; } state->api.emplace(&session->mtp()); state->loading.force_assign(true); const auto done = [=](Settings::SmallBalanceResult result) { if (result == Settings::SmallBalanceResult::Success || result == Settings::SmallBalanceResult::Already) { sendCredits(); } else { state->api = std::nullopt; state->loading.force_assign(false); } }; Settings::MaybeRequestBalanceIncrease( Main::MakeSessionShow(box->uiShow(), session), amount, Settings::SmallBalanceSubscription{ .name = name }, done); }); if (const auto saveButton = state->saveButton) { using namespace Info::Statistics; const auto loadingAnimation = InfiniteRadialAnimationWidget( saveButton, saveButton->height() / 2, &st::editStickerSetNameLoading); AddChildToWidgetCenter(saveButton, loadingAnimation); loadingAnimation->showOn( state->loading.value() | rpl::map(rpl::mappers::_1)); } box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); } void ConfirmInviteBox( not_null box, not_null session, const MTPDchatInvite *invitePtr, ChannelData *invitePeekChannel, Fn submit) { auto invite = ParseInvite(session, *invitePtr); const auto isChannel = invite.isChannel && !invite.isMegagroup; const auto requestApprove = invite.isRequestNeeded; const auto count = invite.participantsCount; struct State { std::shared_ptr photoMedia; std::unique_ptr photoEmpty; std::vector participants; }; const auto state = box->lifetime().make_state(); state->participants = std::move(invite.participants); const auto status = [&] { return invitePeekChannel ? tr::lng_channel_invite_private(tr::now) : (!state->participants.empty() && int(state->participants.size()) < count) ? tr::lng_group_invite_members(tr::now, lt_count, count) : (count > 0 && isChannel) ? tr::lng_chat_status_subscribers( tr::now, lt_count_decimal, count) : (count > 0) ? tr::lng_chat_status_members(tr::now, lt_count_decimal, count) : isChannel ? tr::lng_channel_status(tr::now) : tr::lng_group_status(tr::now); }(); box->setNoContentMargin(true); box->setWidth(st::boxWideWidth); const auto content = box->verticalLayout(); Ui::AddSkip(content, st::confirmInvitePhotoTop); const auto userpic = content->add( object_ptr(content), style::al_top); const auto photoSize = st::confirmInvitePhotoSize; userpic->resize(Size(photoSize)); userpic->setNaturalWidth(photoSize); userpic->paintRequest( ) | rpl::on_next([=, small = Data::PhotoSize::Small] { auto p = QPainter(userpic); if (state->photoMedia) { if (const auto image = state->photoMedia->image(small)) { p.drawPixmap( 0, 0, image->pix( Size(photoSize), { .options = Images::Option::RoundCircle })); } } else if (state->photoEmpty) { state->photoEmpty->paintCircle( p, 0, 0, userpic->width(), photoSize); } }, userpic->lifetime()); userpic->setAttribute(Qt::WA_TransparentForMouseEvents); if (const auto photo = invite.photo) { state->photoMedia = photo->createMediaView(); state->photoMedia->wanted( Data::PhotoSize::Small, Data::FileOrigin()); if (!state->photoMedia->image(Data::PhotoSize::Small)) { session->downloaderTaskFinished( ) | rpl::on_next([=] { userpic->update(); }, userpic->lifetime()); } } else { state->photoEmpty = std::make_unique( Ui::EmptyUserpic::UserpicColor(0), invite.title); } Ui::AddSkip(content); const auto title = box->addRow( object_ptr( box, invite.title, st::confirmInviteTitle), style::al_top); const auto badgeType = BadgeForInvite(invite); if (badgeType != Info::Profile::BadgeType::None) { const auto badgeParent = title->parentWidget(); const auto badge = box->lifetime().make_state( badgeParent, st::infoPeerBadge, session, rpl::single(Info::Profile::Badge::Content{ badgeType }), nullptr, [] { return false; }); title->geometryValue( ) | rpl::on_next([=](const QRect &r) { badge->move(r.x() + r.width(), r.y(), r.y() + r.height()); }, title->lifetime()); } box->addRow( object_ptr( box, status, st::confirmInviteStatus), style::al_top); if (!invite.about.isEmpty()) { box->addRow( object_ptr( box, invite.about, st::confirmInviteAbout), st::confirmInviteAboutPadding, style::al_top); } if (requestApprove) { box->addRow( object_ptr( box, (isChannel ? tr::lng_group_request_about_channel(tr::now) : tr::lng_group_request_about(tr::now)), st::confirmInviteStatus), st::confirmInviteAboutRequestsPadding, style::al_top); } if (!state->participants.empty()) { while (state->participants.size() > 4) { state->participants.pop_back(); } const auto padding = (st::confirmInviteUsersWidth - 4 * st::confirmInviteUserPhotoSize) / 10; const auto userWidth = st::confirmInviteUserPhotoSize + 2 * padding; auto strip = object_ptr(content); const auto rawStrip = strip.data(); rawStrip->resize(st::boxWideWidth, st::confirmInviteUserHeight); rawStrip->setNaturalWidth(st::boxWideWidth); const auto shown = int(state->participants.size()); const auto sumWidth = shown * userWidth; const auto baseLeft = (st::boxWideWidth - sumWidth) / 2; for (auto i = 0; i != shown; ++i) { const auto &participant = state->participants[i]; const auto name = Ui::CreateChild( rawStrip, st::confirmInviteUserName); name->resizeToWidth( st::confirmInviteUserPhotoSize + padding); name->setText(participant.user->firstName.isEmpty() ? participant.user->name() : participant.user->firstName); name->moveToLeft( baseLeft + i * userWidth + (padding / 2), st::confirmInviteUserNameTop - st::confirmInviteUserPhotoTop); } rawStrip->paintRequest( ) | rpl::on_next([=] { auto p = Painter(rawStrip); const auto total = int(state->participants.size()); const auto totalWidth = total * userWidth; auto left = (rawStrip->width() - totalWidth) / 2; for (auto &participant : state->participants) { participant.user->paintUserpicLeft( p, participant.userpic, left + (userWidth - st::confirmInviteUserPhotoSize) / 2, 0, rawStrip->width(), st::confirmInviteUserPhotoSize); left += userWidth; } }, rawStrip->lifetime()); Ui::AddSkip(content, st::boxPadding.bottom()); content->add(std::move(strip), style::margins()); } box->addButton((requestApprove ? tr::lng_group_request_to_join() : isChannel ? tr::lng_profile_join_channel() : tr::lng_profile_join_group()), submit); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); } } // namespace void CheckChatInvite( not_null controller, const QString &hash, ChannelData *invitePeekChannel, Fn loaded) { const auto session = &controller->session(); const auto weak = base::make_weak(controller); session->api().checkChatInvite(hash, [=](const MTPChatInvite &result) { const auto strong = weak.get(); if (!strong) { return; } if (loaded) { loaded(); } Core::App().hideMediaView(); const auto show = [&](not_null chat) { const auto way = Window::SectionShow::Way::Forward; if (const auto forum = chat->forum()) { strong->showForum(forum, way); } else { strong->showPeerHistory(chat, way); } }; result.match([=](const MTPDchatInvite &data) { const auto isGroup = !data.is_broadcast(); const auto hasPricing = !!data.vsubscription_pricing(); const auto canRefulfill = data.is_can_refulfill_subscription(); if (hasPricing && !canRefulfill && !data.vsubscription_form_id()) { strong->uiShow()->showToast( tr::lng_confirm_phone_link_invalid(tr::now)); return; } const auto box = (hasPricing && !canRefulfill) ? strong->show(Box( ConfirmSubscriptionBox, session, hash, &data)) : strong->show(Box( ConfirmInviteBox, session, &data, invitePeekChannel, [=] { SubmitChatInvite(weak, session, hash, isGroup); })); if (invitePeekChannel) { box->boxClosing( ) | rpl::filter([=] { return !invitePeekChannel->amIn(); }) | rpl::on_next([=] { if (const auto strong = weak.get()) { strong->clearSectionStack(Window::SectionShow( Window::SectionShow::Way::ClearStack, anim::type::normal, anim::activation::background)); } }, box->lifetime()); } }, [=](const MTPDchatInviteAlready &data) { if (const auto chat = session->data().processChat(data.vchat())) { if (const auto channel = chat->asChannel()) { channel->clearInvitePeek(); } show(chat); } }, [=](const MTPDchatInvitePeek &data) { if (const auto chat = session->data().processChat(data.vchat())) { if (const auto channel = chat->asChannel()) { channel->setInvitePeek(hash, data.vexpires().v); show(chat); } } }); }, [=](const MTP::Error &error) { if (MTP::IsFloodError(error)) { if (const auto strong = weak.get()) { strong->show(Ui::MakeInformBox(tr::lng_flood_error())); } return; } if (error.code() != 400) { return; } Core::App().hideMediaView(); if (const auto strong = weak.get()) { strong->show(Ui::MakeInformBox(tr::lng_group_invite_bad_link())); } }); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_invite.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once class ChannelData; namespace Main { class Session; } // namespace Main namespace Window { class SessionController; } // namespace Window namespace Api { void CheckChatInvite( not_null controller, const QString &hash, ChannelData *invitePeekChannel = nullptr, Fn loaded = nullptr); } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_links.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_chat_links.h" #include "api/api_text_entities.h" #include "apiwrap.h" #include "data/data_session.h" #include "main/main_session.h" namespace Api { namespace { [[nodiscard]] ChatLink FromMTP( not_null session, const MTPBusinessChatLink &link) { const auto &data = link.data(); return { .link = qs(data.vlink()), .title = qs(data.vtitle().value_or_empty()), .message = { qs(data.vmessage()), EntitiesFromMTP( session, data.ventities().value_or_empty()) }, .clicks = data.vviews().v, }; } [[nodiscard]] MTPInputBusinessChatLink ToMTP( not_null session, const QString &title, const TextWithEntities &message) { auto entities = EntitiesToMTP( session, message.entities, ConvertOption::SkipLocal); using Flag = MTPDinputBusinessChatLink::Flag; const auto flags = (title.isEmpty() ? Flag() : Flag::f_title) | (entities.v.isEmpty() ? Flag() : Flag::f_entities); return MTP_inputBusinessChatLink( MTP_flags(flags), MTP_string(message.text), std::move(entities), MTP_string(title)); } } // namespace ChatLinks::ChatLinks(not_null api) : _api(api) { } void ChatLinks::create( const QString &title, const TextWithEntities &message, Fn done) { const auto session = &_api->session(); _api->request(MTPaccount_CreateBusinessChatLink( ToMTP(session, title, message) )).done([=](const MTPBusinessChatLink &result) { const auto link = FromMTP(session, result); _list.push_back(link); _updates.fire({ .was = QString(), .now = link }); if (done) done(link); }).fail([=](const MTP::Error &error) { const auto type = error.type(); if (done) done(Link()); }).send(); } void ChatLinks::edit( const QString &link, const QString &title, const TextWithEntities &message, Fn done) { const auto session = &_api->session(); _api->request(MTPaccount_EditBusinessChatLink( MTP_string(link), ToMTP(session, title, message) )).done([=](const MTPBusinessChatLink &result) { const auto parsed = FromMTP(session, result); if (parsed.link != link) { LOG(("API Error: EditBusinessChatLink changed the link.")); if (done) done(Link()); return; } const auto i = ranges::find(_list, link, &Link::link); if (i != end(_list)) { *i = parsed; _updates.fire({ .was = link, .now = parsed }); if (done) done(parsed); } else { LOG(("API Error: EditBusinessChatLink link not found.")); if (done) done(Link()); } }).fail([=](const MTP::Error &error) { const auto type = error.type(); if (done) done(Link()); }).send(); } void ChatLinks::destroy( const QString &link, Fn done) { _api->request(MTPaccount_DeleteBusinessChatLink( MTP_string(link) )).done([=] { const auto i = ranges::find(_list, link, &Link::link); if (i != end(_list)) { _list.erase(i); _updates.fire({ .was = link }); if (done) done(); } else { LOG(("API Error: DeleteBusinessChatLink link not found.")); if (done) done(); } }).fail([=](const MTP::Error &error) { const auto type = error.type(); if (done) done(); }).send(); } void ChatLinks::preload() { if (_loaded || _requestId) { return; } _requestId = _api->request(MTPaccount_GetBusinessChatLinks( )).done([=](const MTPaccount_BusinessChatLinks &result) { const auto &data = result.data(); const auto session = &_api->session(); const auto owner = &session->data(); owner->processUsers(data.vusers()); owner->processChats(data.vchats()); auto links = std::vector(); links.reserve(data.vlinks().v.size()); for (const auto &link : data.vlinks().v) { links.push_back(FromMTP(session, link)); } _list = std::move(links); _loaded = true; _loadedUpdates.fire({}); }).fail([=] { _requestId = 0; _loaded = true; _loadedUpdates.fire({}); }).send(); } const std::vector &ChatLinks::list() const { return _list; } bool ChatLinks::loaded() const { return _loaded; } rpl::producer<> ChatLinks::loadedUpdates() const { return _loadedUpdates.events(); } rpl::producer ChatLinks::updates() const { return _updates.events(); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_links.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once class ApiWrap; namespace Api { struct ChatLink { QString link; QString title; TextWithEntities message; int clicks = 0; }; struct ChatLinkUpdate { QString was; std::optional now; }; class ChatLinks final { public: explicit ChatLinks(not_null api); using Link = ChatLink; using Update = ChatLinkUpdate; void create( const QString &title, const TextWithEntities &message, Fn done = nullptr); void edit( const QString &link, const QString &title, const TextWithEntities &message, Fn done = nullptr); void destroy( const QString &link, Fn done = nullptr); void preload(); [[nodiscard]] const std::vector &list() const; [[nodiscard]] bool loaded() const; [[nodiscard]] rpl::producer<> loadedUpdates() const; [[nodiscard]] rpl::producer updates() const; private: const not_null _api; std::vector _list; rpl::event_stream<> _loadedUpdates; mtpRequestId _requestId = 0; bool _loaded = false; rpl::event_stream _updates; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_participants.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_chat_participants.h" #include "apiwrap.h" #include "boxes/add_contact_box.h" // ShowAddParticipantsError #include "boxes/peers/add_participants_box.h" // ChatInviteForbidden #include "data/data_changes.h" #include "data/data_channel.h" #include "data/data_channel_admins.h" #include "data/data_chat.h" #include "data/data_histories.h" #include "data/data_session.h" #include "data/data_user.h" #include "history/history.h" #include "main/main_session.h" #include "mtproto/mtproto_config.h" namespace Api { namespace { using Members = ChatParticipants::Members; constexpr auto kSmallDelayMs = crl::time(5); // 1 second wait before reload members in channel after adding. constexpr auto kReloadChannelMembersTimeout = 1000; // Max users in one super group invite request. constexpr auto kMaxUsersPerInvite = 100; // How many messages from chat history server should forward to user, // that was added to this chat. constexpr auto kForwardMessagesOnAdd = 100; std::vector ParseList( const ChatParticipants::TLMembers &data, not_null peer) { return ranges::views::all( data.vparticipants().v ) | ranges::views::transform([&](const MTPChannelParticipant &p) { return ChatParticipant(p, peer); }) | ranges::to_vector; } void ApplyMegagroupAdmins(not_null channel, Members list) { Expects(channel->isMegagroup()); const auto creatorIt = ranges::find_if( list, &Api::ChatParticipant::isCreator); auto adding = base::flat_set(); auto addingRanks = base::flat_map(); for (const auto &p : list) { if (p.isUser()) { adding.emplace(p.userId()); if (!p.rank().isEmpty()) { addingRanks.emplace(p.userId(), p.rank()); } } } if (creatorIt != list.end() && creatorIt->isUser()) { adding.emplace(creatorIt->userId()); if (!creatorIt->rank().isEmpty()) { addingRanks.emplace(creatorIt->userId(), creatorIt->rank()); } } auto removing = channel->mgInfo->admins; if (removing.empty() && adding.empty()) { LOG(("API Error: Got empty admins list from server.")); adding.emplace(UserId(0)); } Data::ChannelAdminChanges changes(channel); if (creatorIt != list.end()) { creatorIt->tryApplyCreatorTo(channel); } else { channel->mgInfo->creator = nullptr; } for (const auto &addingId : adding) { const auto r = addingRanks.find(addingId); const auto rank = (r != end(addingRanks)) ? r->second : QString(); removing.remove(addingId); changes.add(addingId, rank); } for (const auto &removingId : removing) { changes.remove(removingId); } } void RefreshChannelAdmins( not_null channel, Members participants) { Data::ChannelAdminChanges changes(channel); for (const auto &p : participants) { if (p.isUser()) { if (p.isCreatorOrAdmin()) { p.tryApplyCreatorTo(channel); changes.add(p.userId(), p.rank()); } else { changes.remove(p.userId()); } } } } void ApplyLastList( not_null channel, int availableCount, Members list) { channel->mgInfo->lastAdmins.clear(); channel->mgInfo->lastRestricted.clear(); channel->mgInfo->lastParticipants.clear(); channel->mgInfo->memberRanks.clear(); channel->mgInfo->lastParticipantsStatus = MegagroupInfo::LastParticipantsUpToDate | MegagroupInfo::LastParticipantsOnceReceived; auto botStatus = channel->mgInfo->botStatus; for (const auto &p : list) { const auto participant = channel->owner().peer(p.id()); const auto user = participant->asUser(); const auto adminRights = p.rights(); const auto restrictedRights = p.restrictions(); if (p.isCreator()) { Assert(user != nullptr); p.tryApplyCreatorTo(channel); if (!channel->mgInfo->admins.empty()) { Data::ChannelAdminChanges(channel).add(p.userId(), p.rank()); } } if (user && !base::contains(channel->mgInfo->lastParticipants, user)) { channel->mgInfo->lastParticipants.push_back(user); if (adminRights.flags) { channel->mgInfo->lastAdmins.emplace( user, MegagroupInfo::Admin{ adminRights, p.canBeEdited() }); } else if (restrictedRights.flags) { channel->mgInfo->lastRestricted.emplace( user, MegagroupInfo::Restricted{ restrictedRights }); } if (user->isBot()) { channel->mgInfo->bots.insert(user); if (channel->mgInfo->botStatus == Data::BotStatus::NoBots) { channel->mgInfo->botStatus = Data::BotStatus::HasBots; } } if (!p.rank().isEmpty()) { channel->mgInfo->memberRanks[p.userId()] = p.rank(); } } } // // getParticipants(Recent) sometimes can't return all members, // only some last subset, size of this subset is availableCount. // // So both list size and availableCount have nothing to do with // the full supergroup members count. // //if (list.isEmpty()) { // channel->setMembersCount(channel->mgInfo->lastParticipants.size()); //} else { // channel->setMembersCount(availableCount); //} channel->session().changes().peerUpdated( channel, (Data::PeerUpdate::Flag::Members | Data::PeerUpdate::Flag::Admins)); channel->mgInfo->botStatus = botStatus; channel->session().changes().peerUpdated( channel, Data::PeerUpdate::Flag::FullInfo); } void ApplyBotsList( not_null channel, int availableCount, Members list) { const auto history = channel->owner().historyLoaded(channel); channel->mgInfo->bots.clear(); channel->mgInfo->botStatus = Data::BotStatus::NoBots; auto needBotsInfos = false; auto botStatus = channel->mgInfo->botStatus; auto keyboardBotFound = !history || !history->lastKeyboardFrom; for (const auto &p : list) { const auto participant = channel->owner().peer(p.id()); const auto user = participant->asUser(); if (user && user->isBot()) { channel->mgInfo->bots.insert(user); botStatus = Data::BotStatus::HasBots; if (!user->botInfo->inited) { needBotsInfos = true; } } if (!keyboardBotFound && participant->id == history->lastKeyboardFrom) { keyboardBotFound = true; } } if (needBotsInfos) { channel->session().api().requestFullPeer(channel); } if (!keyboardBotFound) { history->clearLastKeyboard(); } channel->mgInfo->botStatus = botStatus; channel->session().changes().peerUpdated( channel, Data::PeerUpdate::Flag::FullInfo); } [[nodiscard]] ChatParticipants::Peers ParseSimilarChannels( not_null session, const MTPmessages_Chats &chats) { auto result = ChatParticipants::Peers(); chats.match([&](const auto &data) { const auto &list = data.vchats().v; result.list.reserve(list.size()); for (const auto &chat : list) { const auto peer = session->data().processChat(chat); if (const auto channel = peer->asChannel()) { result.list.push_back(channel); } } if constexpr (MTPDmessages_chatsSlice::Is()) { if (session->premiumPossible()) { result.more = data.vcount().v - data.vchats().v.size(); } } }); return result; } [[nodiscard]] ChatParticipants::Peers ParseSimilarChannels( not_null channel, const MTPmessages_Chats &chats) { return ParseSimilarChannels(&channel->session(), chats); } [[nodiscard]] ChatParticipants::Peers ParseSimilarBots( not_null session, const MTPusers_Users &users) { auto result = ChatParticipants::Peers(); users.match([&](const auto &data) { const auto &list = data.vusers().v; result.list.reserve(list.size()); for (const auto &user : list) { result.list.push_back(session->data().processUser(user)); } if constexpr (MTPDusers_usersSlice::Is()) { if (session->premiumPossible()) { result.more = data.vcount().v - data.vusers().v.size(); } } }); return result; } } // namespace ChatParticipant::ChatParticipant( const MTPChannelParticipant &p, not_null peer) { _peer = p.match([](const MTPDchannelParticipantBanned &data) { return peerFromMTP(data.vpeer()); }, [](const MTPDchannelParticipantLeft &data) { return peerFromMTP(data.vpeer()); }, [](const auto &data) { return peerFromUser(data.vuser_id()); }); p.match([&](const MTPDchannelParticipantCreator &data) { _canBeEdited = (peer->session().userPeerId() == _peer); _type = Type::Creator; _rights = ChatAdminRightsInfo(data.vadmin_rights()); _rank = qs(data.vrank().value_or_empty()); }, [&](const MTPDchannelParticipantAdmin &data) { _canBeEdited = data.is_can_edit(); _type = Type::Admin; _rank = qs(data.vrank().value_or_empty()); _rights = ChatAdminRightsInfo(data.vadmin_rights()); _by = peerToUser(peerFromUser(data.vpromoted_by())); _date = data.vdate().v; }, [&](const MTPDchannelParticipantSelf &data) { _type = Type::Member; _date = data.vdate().v; _by = peerToUser(peerFromUser(data.vinviter_id())); _rank = qs(data.vrank().value_or_empty()); if (data.vsubscription_until_date()) { _subscriptionDate = data.vsubscription_until_date()->v; } }, [&](const MTPDchannelParticipant &data) { _type = Type::Member; _date = data.vdate().v; _rank = qs(data.vrank().value_or_empty()); if (data.vsubscription_until_date()) { _subscriptionDate = data.vsubscription_until_date()->v; } }, [&](const MTPDchannelParticipantBanned &data) { _restrictions = ChatRestrictionsInfo(data.vbanned_rights()); _by = peerToUser(peerFromUser(data.vkicked_by())); _date = data.vdate().v; _rank = qs(data.vrank().value_or_empty()); _type = (_restrictions.flags & ChatRestriction::ViewMessages) ? Type::Banned : Type::Restricted; }, [&](const MTPDchannelParticipantLeft &data) { _type = Type::Left; }); } ChatParticipant::ChatParticipant( Type type, PeerId peerId, UserId by, ChatRestrictionsInfo restrictions, ChatAdminRightsInfo rights, bool canBeEdited, QString rank) : _type(type) , _peer(peerId) , _by(by) , _canBeEdited(canBeEdited) , _rank(rank) , _restrictions(std::move(restrictions)) , _rights(std::move(rights)) { } void ChatParticipant::tryApplyCreatorTo( not_null channel) const { if (isCreator() && isUser()) { if (const auto info = channel->mgInfo.get()) { info->creator = channel->owner().userLoaded(userId()); if (!rank().isEmpty()) { info->memberRanks[userId()] = rank(); } else { info->memberRanks.remove(userId()); } } } } bool ChatParticipant::isUser() const { return peerIsUser(_peer); } bool ChatParticipant::isCreator() const { return _type == Type::Creator; } bool ChatParticipant::isCreatorOrAdmin() const { return _type == Type::Creator || _type == Type::Admin; } bool ChatParticipant::isKicked() const { return _type == Type::Banned; } bool ChatParticipant::canBeEdited() const { return _canBeEdited; } UserId ChatParticipant::by() const { return _by; } PeerId ChatParticipant::id() const { return _peer; } UserId ChatParticipant::userId() const { return peerToUser(_peer); } ChatRestrictionsInfo ChatParticipant::restrictions() const { return _restrictions; } ChatAdminRightsInfo ChatParticipant::rights() const { return _rights; } TimeId ChatParticipant::subscriptionDate() const { return _subscriptionDate; } TimeId ChatParticipant::promotedSince() const { return (_type == Type::Admin) ? _date : TimeId(0); } TimeId ChatParticipant::restrictedSince() const { return (_type == Type::Restricted || _type == Type::Banned) ? _date : TimeId(0); } TimeId ChatParticipant::memberSince() const { return (_type == Type::Member) ? _date : TimeId(0); } ChatParticipant::Type ChatParticipant::type() const { return _type; } QString ChatParticipant::rank() const { return _rank; } ChatParticipants::ChatParticipants(not_null api) : _session(&api->session()) , _api(&api->instance()) { } void ChatParticipants::requestForAdd( not_null channel, Fn callback) { Expects(callback != nullptr); _forAdd.callback = std::move(callback); if (_forAdd.channel == channel) { return; } _api.request(base::take(_forAdd.requestId)).cancel(); const auto offset = 0; const auto participantsHash = uint64(0); _forAdd.channel = channel; _forAdd.requestId = _api.request(MTPchannels_GetParticipants( channel->inputChannel(), MTP_channelParticipantsRecent(), MTP_int(offset), MTP_int(channel->session().serverConfig().chatSizeMax), MTP_long(participantsHash) )).done([=](const MTPchannels_ChannelParticipants &result) { result.match([&](const MTPDchannels_channelParticipants &data) { base::take(_forAdd).callback(data); }, [&](const MTPDchannels_channelParticipantsNotModified &) { base::take(_forAdd); LOG(("API Error: " "channels.channelParticipantsNotModified received!")); }); }).fail([=] { base::take(_forAdd); }).send(); } void ChatParticipants::requestLast(not_null channel) { if (!channel->isMegagroup() || !channel->canViewMembers() || _participantsRequests.contains(channel)) { return; } const auto offset = 0; const auto participantsHash = uint64(0); const auto requestId = _api.request(MTPchannels_GetParticipants( channel->inputChannel(), MTP_channelParticipantsRecent(), MTP_int(offset), MTP_int(channel->session().serverConfig().chatSizeMax), MTP_long(participantsHash) )).done([=](const MTPchannels_ChannelParticipants &result) { _participantsRequests.remove(channel); result.match([&](const MTPDchannels_channelParticipants &data) { const auto &[availableCount, list] = Parse(channel, data); ApplyLastList(channel, availableCount, list); }, [](const MTPDchannels_channelParticipantsNotModified &) { LOG(("API Error: " "channels.channelParticipantsNotModified received!")); }); }).fail([this, channel] { _participantsRequests.remove(channel); }).send(); _participantsRequests[channel] = requestId; } void ChatParticipants::requestBots(not_null channel) { if (!channel->isMegagroup() || _botsRequests.contains(channel)) { return; } const auto offset = 0; const auto participantsHash = uint64(0); const auto requestId = _api.request(MTPchannels_GetParticipants( channel->inputChannel(), MTP_channelParticipantsBots(), MTP_int(offset), MTP_int(channel->session().serverConfig().chatSizeMax), MTP_long(participantsHash) )).done([=](const MTPchannels_ChannelParticipants &result) { _botsRequests.remove(channel); result.match([&](const MTPDchannels_channelParticipants &data) { const auto &[availableCount, list] = Parse(channel, data); ApplyBotsList(channel, availableCount, list); }, [](const MTPDchannels_channelParticipantsNotModified &) { LOG(("API Error: " "channels.channelParticipantsNotModified received!")); }); }).fail([=](const MTP::Error &error) { _botsRequests.remove(channel); if (error.type() == u"CHANNEL_MONOFORUM_UNSUPPORTED"_q) { channel->mgInfo->bots.clear(); channel->mgInfo->botStatus = Data::BotStatus::NoBots; channel->session().changes().peerUpdated( channel, Data::PeerUpdate::Flag::FullInfo); } }).send(); _botsRequests[channel] = requestId; } void ChatParticipants::requestAdmins(not_null channel) { if (!channel->isMegagroup() || _adminsRequests.contains(channel)) { return; } const auto offset = 0; const auto participantsHash = uint64(0); const auto requestId = _api.request(MTPchannels_GetParticipants( channel->inputChannel(), MTP_channelParticipantsAdmins(), MTP_int(offset), MTP_int(channel->session().serverConfig().chatSizeMax), MTP_long(participantsHash) )).done([=](const MTPchannels_ChannelParticipants &result) { channel->mgInfo->adminsLoaded = true; _adminsRequests.remove(channel); result.match([&](const MTPDchannels_channelParticipants &data) { channel->owner().processUsers(data.vusers()); ApplyMegagroupAdmins(channel, ParseList(data, channel)); }, [](const MTPDchannels_channelParticipantsNotModified &) { LOG(("API Error: " "channels.channelParticipantsNotModified received!")); }); }).fail([=] { channel->mgInfo->adminsLoaded = true; _adminsRequests.remove(channel); }).send(); _adminsRequests[channel] = requestId; } void ChatParticipants::requestCountDelayed( not_null channel) { _participantsCountRequestTimer.call( kReloadChannelMembersTimeout, [=] { channel->updateFullForced(); }); } void ChatParticipants::add( std::shared_ptr show, not_null peer, const std::vector> &users, bool passGroupHistory, Fn done) { if (const auto chat = peer->asChat()) { for (const auto &user : users) { _api.request(MTPmessages_AddChatUser( chat->inputChat(), user->inputUser(), MTP_int(passGroupHistory ? kForwardMessagesOnAdd : 0) )).done([=](const MTPmessages_InvitedUsers &result) { const auto &data = result.data(); chat->session().api().applyUpdates(data.vupdates()); if (done) done(true); ChatInviteForbidden( show, chat, CollectForbiddenUsers(&chat->session(), result)); }).fail([=](const MTP::Error &error) { const auto type = error.type(); ShowAddParticipantsError(show, type, peer, user); if (done) done(false); }).afterDelay(kSmallDelayMs).send(); } } else if (const auto channel = peer->asChannel()) { const auto hasBot = ranges::any_of(users, &UserData::isBot); if (!peer->isMegagroup() && hasBot) { ShowAddParticipantsError( show, u"USER_BOT"_q, peer, { .users = users }); return; } auto list = QVector(); list.reserve(std::min(int(users.size()), int(kMaxUsersPerInvite))); const auto send = [&] { const auto callback = base::take(done); _api.request(MTPchannels_InviteToChannel( channel->inputChannel(), MTP_vector(list) )).done([=](const MTPmessages_InvitedUsers &result) { const auto &data = result.data(); channel->session().api().applyUpdates(data.vupdates()); requestCountDelayed(channel); if (callback) callback(true); ChatInviteForbidden( show, channel, CollectForbiddenUsers(&channel->session(), result)); }).fail([=](const MTP::Error &error) { ShowAddParticipantsError(show, error.type(), peer, { .users = users, }); if (callback) callback(false); }).afterDelay(kSmallDelayMs).send(); }; for (const auto &user : users) { list.push_back(user->inputUser()); if (list.size() == kMaxUsersPerInvite) { send(); list.clear(); } } if (!list.empty()) { send(); } } else { Unexpected("User in ChatParticipants::add."); } } ChatParticipants::Parsed ChatParticipants::Parse( not_null channel, const TLMembers &data) { channel->owner().processUsers(data.vusers()); channel->owner().processChats(data.vchats()); auto list = ParseList(data, channel); if (channel->mgInfo) { RefreshChannelAdmins(channel, list); } return { data.vcount().v, std::move(list) }; } ChatParticipants::Parsed ChatParticipants::ParseRecent( not_null channel, const TLMembers &data) { const auto result = Parse(channel, data); const auto applyLast = channel->isMegagroup() && channel->canViewMembers() && (channel->mgInfo->lastParticipants.size() <= result.list.size()); if (applyLast) { ApplyLastList(channel, result.availableCount, result.list); } return result; } void ChatParticipants::Restrict( not_null channel, not_null participant, ChatRestrictionsInfo oldRights, ChatRestrictionsInfo newRights, Fn onDone, Fn onFail) { channel->session().api().request(MTPchannels_EditBanned( channel->inputChannel(), participant->input(), RestrictionsToMTP(newRights) )).done([=](const MTPUpdates &result) { channel->session().api().applyUpdates(result); channel->applyEditBanned(participant, oldRights, newRights); if (onDone) { onDone(); } }).fail([=](const MTP::Error &error) { if (onFail) { onFail(error.type()); } }).send(); } void ChatParticipants::requestSelf(not_null channel) { if (_selfParticipantRequests.contains(channel)) { return; } const auto finalize = [=]( UserId inviter = -1, TimeId inviteDate = 0, bool inviteViaRequest = false) { channel->inviter = inviter; channel->inviteDate = inviteDate; channel->inviteViaRequest = inviteViaRequest; if (const auto history = channel->owner().historyLoaded(channel)) { if (history->lastMessageKnown()) { history->checkLocalMessages(); history->owner().sendHistoryChangeNotifications(); } else { history->owner().histories().requestDialogEntry(history); } } }; _selfParticipantRequests.emplace(channel); _api.request(MTPchannels_GetParticipant( channel->inputChannel(), MTP_inputPeerSelf() )).done([=](const MTPchannels_ChannelParticipant &result) { _selfParticipantRequests.erase(channel); result.match([&](const MTPDchannels_channelParticipant &data) { channel->owner().processUsers(data.vusers()); const auto &participant = data.vparticipant(); participant.match([&](const MTPDchannelParticipantSelf &data) { finalize( data.vinviter_id().v, data.vdate().v, data.is_via_request()); }, [&](const MTPDchannelParticipantCreator &) { if (channel->mgInfo) { channel->mgInfo->creator = channel->session().user(); } finalize(channel->session().userId(), channel->date); }, [&](const MTPDchannelParticipantAdmin &data) { const auto inviter = data.is_self() ? data.vinviter_id().value_or(-1) : -1; finalize(inviter, data.vdate().v); }, [&](const MTPDchannelParticipantBanned &data) { LOG(("API Error: Got self banned participant.")); finalize(); }, [&](const MTPDchannelParticipant &data) { LOG(("API Error: Got self regular participant.")); finalize(); }, [&](const MTPDchannelParticipantLeft &data) { LOG(("API Error: Got self left participant.")); finalize(); }); }); }).fail([=](const MTP::Error &error) { _selfParticipantRequests.erase(channel); if (error.type() == u"CHANNEL_PRIVATE"_q) { channel->privateErrorReceived(); } finalize(); }).afterDelay(kSmallDelayMs).send(); } void ChatParticipants::kick( not_null chat, not_null participant) { Expects(participant->isUser()); _api.request(MTPmessages_DeleteChatUser( MTP_flags(0), chat->inputChat(), participant->asUser()->inputUser() )).done([=](const MTPUpdates &result) { chat->session().api().applyUpdates(result); }).send(); } void ChatParticipants::kick( not_null channel, not_null participant, ChatRestrictionsInfo currentRights) { const auto kick = KickRequest(channel, participant); if (_kickRequests.contains(kick)) return; const auto rights = ChannelData::KickedRestrictedRights(participant); const auto requestId = _api.request(MTPchannels_EditBanned( channel->inputChannel(), participant->input(), RestrictionsToMTP(rights) )).done([=](const MTPUpdates &result) { channel->session().api().applyUpdates(result); _kickRequests.remove(KickRequest(channel, participant)); channel->applyEditBanned(participant, currentRights, rights); }).fail([this, kick] { _kickRequests.remove(kick); }).send(); _kickRequests.emplace(kick, requestId); } void ChatParticipants::unblock( not_null channel, not_null participant) { const auto kick = KickRequest(channel, participant); if (_kickRequests.contains(kick)) { return; } const auto requestId = _api.request(MTPchannels_EditBanned( channel->inputChannel(), participant->input(), MTP_chatBannedRights(MTP_flags(0), MTP_int(0)) )).done([=](const MTPUpdates &result) { channel->session().api().applyUpdates(result); _kickRequests.remove(KickRequest(channel, participant)); if (channel->kickedCount() > 0) { channel->setKickedCount(channel->kickedCount() - 1); } else { channel->updateFullForced(); } }).fail([=] { _kickRequests.remove(kick); }).send(); _kickRequests.emplace(kick, requestId); } void ChatParticipants::loadSimilarPeers(not_null peer) { if (const auto i = _similar.find(peer); i != end(_similar)) { if (i->second.requestId || !i->second.peers.more || !peer->session().premium()) { return; } } if (const auto channel = peer->asBroadcast()) { using Flag = MTPchannels_GetChannelRecommendations::Flag; _similar[peer].requestId = _api.request( MTPchannels_GetChannelRecommendations( MTP_flags(Flag::f_channel), channel->inputChannel()) ).done([=](const MTPmessages_Chats &result) { auto &similar = _similar[channel]; similar.requestId = 0; auto parsed = ParseSimilarChannels(channel, result); if (similar.peers == parsed) { return; } similar.peers = std::move(parsed); if (const auto history = channel->owner().historyLoaded(channel)) { if (const auto item = history->joinedMessageInstance()) { history->owner().requestItemResize(item); } } _similarLoaded.fire_copy(channel); }).send(); } else if (const auto bot = peer->asBot()) { _similar[peer].requestId = _api.request( MTPbots_GetBotRecommendations(bot->inputUser()) ).done([=](const MTPusers_Users &result) { auto &similar = _similar[peer]; similar.requestId = 0; auto parsed = ParseSimilarBots(&peer->session(), result); if (similar.peers == parsed) { return; } similar.peers = std::move(parsed); _similarLoaded.fire_copy(peer); }).send(); } } auto ChatParticipants::similar(not_null peer) -> const Peers & { const auto i = (peer->isBroadcast() || peer->isBot()) ? _similar.find(peer) : end(_similar); if (i != end(_similar)) { return i->second.peers; } static const auto empty = Peers(); return empty; } auto ChatParticipants::similarLoaded() const -> rpl::producer> { return _similarLoaded.events(); } void ChatParticipants::loadRecommendations() { if (_recommendationsLoaded.current() || _recommendations.requestId) { return; } _recommendations.requestId = _api.request( MTPchannels_GetChannelRecommendations( MTP_flags(0), MTP_inputChannelEmpty()) ).done([=](const MTPmessages_Chats &result) { _recommendations.requestId = 0; auto parsed = ParseSimilarChannels(_session, result); _recommendations.peers = std::move(parsed); _recommendations.peers.more = 0; _recommendationsLoaded = true; }).send(); } const ChatParticipants::Peers &ChatParticipants::recommendations() const { return _recommendations.peers; } rpl::producer<> ChatParticipants::recommendationsLoaded() const { return _recommendationsLoaded.changes() | rpl::to_empty; } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_chat_participants.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "data/data_chat_participant_status.h" #include "mtproto/sender.h" #include "base/timer.h" class ApiWrap; class ChannelData; namespace Main { class Session; } // namespace Main namespace Ui { class Show; } // namespace Ui namespace Api { class ChatParticipant final { public: enum class Type { Creator, Admin, Member, Restricted, Left, Banned, }; explicit ChatParticipant( const MTPChannelParticipant &p, not_null peer); ChatParticipant( Type type, PeerId peerId, UserId by, ChatRestrictionsInfo restrictions, ChatAdminRightsInfo rights, bool canBeEdited = false, QString rank = QString()); bool isUser() const; bool isCreator() const; bool isCreatorOrAdmin() const; bool isKicked() const; bool canBeEdited() const; UserId by() const; PeerId id() const; UserId userId() const; ChatRestrictionsInfo restrictions() const; ChatAdminRightsInfo rights() const; TimeId subscriptionDate() const; TimeId promotedSince() const; TimeId restrictedSince() const; TimeId memberSince() const; Type type() const; QString rank() const; void tryApplyCreatorTo(not_null channel) const; private: Type _type = Type::Member; PeerId _peer; UserId _by; // Banned/Restricted/Promoted. bool _canBeEdited = false; QString _rank; TimeId _subscriptionDate = 0; TimeId _date = 0; ChatRestrictionsInfo _restrictions; ChatAdminRightsInfo _rights; }; class ChatParticipants final { public: struct Parsed { const int availableCount; const std::vector list; }; using TLMembers = MTPDchannels_channelParticipants; using Members = const std::vector &; explicit ChatParticipants(not_null api); void requestLast(not_null channel); void requestBots(not_null channel); void requestAdmins(not_null channel); void requestCountDelayed(not_null channel); static Parsed Parse( not_null channel, const TLMembers &data); static Parsed ParseRecent( not_null channel, const TLMembers &data); static void Restrict( not_null channel, not_null participant, ChatRestrictionsInfo oldRights, ChatRestrictionsInfo newRights, Fn onDone, Fn onFail); void add( std::shared_ptr show, not_null peer, const std::vector> &users, bool passGroupHistory = true, Fn done = nullptr); void requestSelf(not_null channel); void requestForAdd( not_null channel, Fn callback); void kick( not_null chat, not_null participant); void kick( not_null channel, not_null participant, ChatRestrictionsInfo currentRights); void unblock( not_null channel, not_null participant); void loadSimilarPeers(not_null peer); struct Peers { std::vector> list; int more = 0; friend inline bool operator==( const Peers &, const Peers &) = default; }; [[nodiscard]] const Peers &similar(not_null peer); [[nodiscard]] auto similarLoaded() const -> rpl::producer>; void loadRecommendations(); [[nodiscard]] const Peers &recommendations() const; [[nodiscard]] rpl::producer<> recommendationsLoaded() const; private: struct SimilarPeers { Peers peers; mtpRequestId requestId = 0; }; const not_null _session; MTP::Sender _api; using PeerRequests = base::flat_map; PeerRequests _participantsRequests; PeerRequests _botsRequests; PeerRequests _adminsRequests; base::DelayedCallTimer _participantsCountRequestTimer; struct { ChannelData *channel = nullptr; mtpRequestId requestId = 0; Fn callback; } _forAdd; base::flat_set> _selfParticipantRequests; using KickRequest = std::pair< not_null, not_null>; base::flat_map _kickRequests; base::flat_map, SimilarPeers> _similar; rpl::event_stream> _similarLoaded; SimilarPeers _recommendations; rpl::variable _recommendationsLoaded = false; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_cloud_password.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_cloud_password.h" #include "apiwrap.h" #include "base/random.h" #include "core/core_cloud_password.h" #include "passport/passport_encryption.h" #include "base/unixtime.h" #include "base/call_delayed.h" namespace Api { namespace { [[nodiscard]] Core::CloudPasswordState ProcessMtpState( const MTPaccount_password &state) { return state.match([&](const MTPDaccount_password &data) { base::RandomAddSeed(bytes::make_span(data.vsecure_random().v)); return Core::ParseCloudPasswordState(data); }); } } // namespace CloudPassword::CloudPassword(not_null api) : _api(&api->instance()) { } void CloudPassword::apply(Core::CloudPasswordState state) { if (_state) { *_state = std::move(state); } else { _state = std::make_unique(std::move(state)); } _stateChanges.fire_copy(*_state); } void CloudPassword::reload() { if (_requestId) { return; } _requestId = _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { _requestId = 0; apply(ProcessMtpState(result)); }).fail([=] { _requestId = 0; }).send(); } void CloudPassword::clearUnconfirmedPassword() { _requestId = _api.request(MTPaccount_CancelPasswordEmail( )).done([=] { _requestId = 0; reload(); }).fail([=] { _requestId = 0; reload(); }).send(); } rpl::producer CloudPassword::state() const { return _state ? _stateChanges.events_starting_with_copy(*_state) : (_stateChanges.events() | rpl::type_erased); } auto CloudPassword::stateCurrent() const -> std::optional { return _state ? base::make_optional(*_state) : std::nullopt; } auto CloudPassword::resetPassword() -> rpl::producer { return [=](auto consumer) { _api.request(MTPaccount_ResetPassword( )).done([=](const MTPaccount_ResetPasswordResult &result) { result.match([&](const MTPDaccount_resetPasswordOk &data) { reload(); }, [&](const MTPDaccount_resetPasswordRequestedWait &data) { if (!_state) { reload(); return; } const auto until = data.vuntil_date().v; if (_state->pendingResetDate != until) { _state->pendingResetDate = until; _stateChanges.fire_copy(*_state); } }, [&](const MTPDaccount_resetPasswordFailedWait &data) { consumer.put_next_copy(data.vretry_date().v); }); consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return rpl::lifetime(); }; } auto CloudPassword::cancelResetPassword() -> rpl::producer { return [=](auto consumer) { _api.request(MTPaccount_DeclinePasswordReset( )).done([=] { reload(); consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return rpl::lifetime(); }; } rpl::producer CloudPassword::set( const QString &oldPassword, const QString &newPassword, const QString &hint, bool hasRecoveryEmail, const QString &recoveryEmail) { const auto generatePasswordCheck = [=]( const Core::CloudPasswordState &latestState) { if (oldPassword.isEmpty() || !latestState.hasPassword) { return Core::CloudPasswordResult{ MTP_inputCheckPasswordEmpty() }; } const auto hash = Core::ComputeCloudPasswordHash( latestState.mtp.request.algo, bytes::make_span(oldPassword.toUtf8())); return Core::ComputeCloudPasswordCheck( latestState.mtp.request, hash); }; const auto finish = [=](auto consumer, int unconfirmedEmailLengthCode) { _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { apply(ProcessMtpState(result)); if (unconfirmedEmailLengthCode) { consumer.put_next(SetOk{ unconfirmedEmailLengthCode }); } else { consumer.put_done(); } }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).handleFloodErrors().send(); }; const auto sendMTPaccountUpdatePasswordSettings = [=]( const Core::CloudPasswordState &latestState, const QByteArray &secureSecret, auto consumer) { const auto newPasswordBytes = newPassword.toUtf8(); const auto newPasswordHash = Core::ComputeCloudPasswordDigest( latestState.mtp.newPassword, bytes::make_span(newPasswordBytes)); if (!newPassword.isEmpty() && newPasswordHash.modpow.empty()) { consumer.put_error("INTERNAL_SERVER_ERROR"); return; } using Flag = MTPDaccount_passwordInputSettings::Flag; const auto flags = Flag::f_new_algo | Flag::f_new_password_hash | Flag::f_hint | (secureSecret.isEmpty() ? Flag(0) : Flag::f_new_secure_settings) | ((!hasRecoveryEmail) ? Flag(0) : Flag::f_email); auto newSecureSecret = bytes::vector(); auto newSecureSecretId = 0ULL; if (!secureSecret.isEmpty()) { newSecureSecretId = Passport::CountSecureSecretId( bytes::make_span(secureSecret)); newSecureSecret = Passport::EncryptSecureSecret( bytes::make_span(secureSecret), Core::ComputeSecureSecretHash( latestState.mtp.newSecureSecret, bytes::make_span(newPasswordBytes))); } const auto settings = MTP_account_passwordInputSettings( MTP_flags(flags), Core::PrepareCloudPasswordAlgo(newPassword.isEmpty() ? v::null : latestState.mtp.newPassword), newPassword.isEmpty() ? MTP_bytes() : MTP_bytes(newPasswordHash.modpow), MTP_string(hint), MTP_string(recoveryEmail), MTP_secureSecretSettings( Core::PrepareSecureSecretAlgo( latestState.mtp.newSecureSecret), MTP_bytes(newSecureSecret), MTP_long(newSecureSecretId))); _api.request(MTPaccount_UpdatePasswordSettings( generatePasswordCheck(latestState).result, settings )).done([=] { finish(consumer, 0); }).fail([=](const MTP::Error &error) { const auto &type = error.type(); const auto prefix = u"EMAIL_UNCONFIRMED_"_q; if (type.startsWith(prefix)) { const auto codeLength = base::StringViewMid( type, prefix.size()).toInt(); finish(consumer, codeLength); } else { consumer.put_error_copy(type); } }).handleFloodErrors().send(); }; return [=](auto consumer) { _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { const auto latestState = ProcessMtpState(result); if (latestState.hasPassword && !oldPassword.isEmpty() && !newPassword.isEmpty()) { _api.request(MTPaccount_GetPasswordSettings( generatePasswordCheck(latestState).result )).done([=](const MTPaccount_PasswordSettings &result) { using Settings = MTPDaccount_passwordSettings; const auto &data = result.match([&]( const Settings &data) -> const Settings & { return data; }); auto secureSecret = QByteArray(); if (const auto wrapped = data.vsecure_settings()) { using Secure = MTPDsecureSecretSettings; const auto &settings = wrapped->match([]( const Secure &data) -> const Secure & { return data; }); const auto passwordUtf = oldPassword.toUtf8(); const auto secret = Passport::DecryptSecureSecret( bytes::make_span(settings.vsecure_secret().v), Core::ComputeSecureSecretHash( Core::ParseSecureSecretAlgo( settings.vsecure_algo()), bytes::make_span(passwordUtf))); if (secret.empty()) { LOG(("API Error: " "Failed to decrypt secure secret.")); consumer.put_error("SUGGEST_SECRET_RESET"); return; } else if (Passport::CountSecureSecretId(secret) != settings.vsecure_secret_id().v) { LOG(("API Error: Wrong secure secret id.")); consumer.put_error("SUGGEST_SECRET_RESET"); return; } else { secureSecret = QByteArray( reinterpret_cast(secret.data()), secret.size()); } } _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { const auto latestState = ProcessMtpState(result); sendMTPaccountUpdatePasswordSettings( latestState, secureSecret, consumer); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); } else { sendMTPaccountUpdatePasswordSettings( latestState, QByteArray(), consumer); } }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return rpl::lifetime(); }; } rpl::producer CloudPassword::check( const QString &password) { return [=](auto consumer) { _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { const auto latestState = ProcessMtpState(result); const auto input = [&] { if (password.isEmpty()) { return Core::CloudPasswordResult{ MTP_inputCheckPasswordEmpty() }; } const auto hash = Core::ComputeCloudPasswordHash( latestState.mtp.request.algo, bytes::make_span(password.toUtf8())); return Core::ComputeCloudPasswordCheck( latestState.mtp.request, hash); }(); _api.request(MTPaccount_GetPasswordSettings( input.result )).done([=](const MTPaccount_PasswordSettings &result) { consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return rpl::lifetime(); }; } rpl::producer CloudPassword::confirmEmail( const QString &code) { return [=](auto consumer) { _api.request(MTPaccount_ConfirmPasswordEmail( MTP_string(code) )).done([=] { _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { apply(ProcessMtpState(result)); consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).handleFloodErrors().send(); return rpl::lifetime(); }; } rpl::producer CloudPassword::resendEmailCode() { return [=](auto consumer) { _api.request(MTPaccount_ResendPasswordEmail( )).done([=] { _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { apply(ProcessMtpState(result)); consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).handleFloodErrors().send(); return rpl::lifetime(); }; } rpl::producer CloudPassword::setEmail( const QString &oldPassword, const QString &recoveryEmail) { const auto generatePasswordCheck = [=]( const Core::CloudPasswordState &latestState) { if (oldPassword.isEmpty() || !latestState.hasPassword) { return Core::CloudPasswordResult{ MTP_inputCheckPasswordEmpty() }; } const auto hash = Core::ComputeCloudPasswordHash( latestState.mtp.request.algo, bytes::make_span(oldPassword.toUtf8())); return Core::ComputeCloudPasswordCheck( latestState.mtp.request, hash); }; const auto finish = [=](auto consumer, int unconfirmedEmailLengthCode) { _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { apply(ProcessMtpState(result)); if (unconfirmedEmailLengthCode) { consumer.put_next(SetOk{ unconfirmedEmailLengthCode }); } else { consumer.put_done(); } }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).handleFloodErrors().send(); }; const auto sendMTPaccountUpdatePasswordSettings = [=]( const Core::CloudPasswordState &latestState, auto consumer) { const auto settings = MTP_account_passwordInputSettings( MTP_flags(MTPDaccount_passwordInputSettings::Flag::f_email), MTP_passwordKdfAlgoUnknown(), MTP_bytes(), MTP_string(), MTP_string(recoveryEmail), MTPSecureSecretSettings()); _api.request(MTPaccount_UpdatePasswordSettings( generatePasswordCheck(latestState).result, settings )).done([=] { finish(consumer, 0); }).fail([=](const MTP::Error &error) { const auto &type = error.type(); const auto prefix = u"EMAIL_UNCONFIRMED_"_q; if (type.startsWith(prefix)) { const auto codeLength = base::StringViewMid( type, prefix.size()).toInt(); finish(consumer, codeLength); } else { consumer.put_error_copy(type); } }).handleFloodErrors().send(); }; return [=](auto consumer) { _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { const auto latestState = ProcessMtpState(result); sendMTPaccountUpdatePasswordSettings(latestState, consumer); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return rpl::lifetime(); }; } rpl::producer CloudPassword::recoverPassword( const QString &code, const QString &newPassword, const QString &newHint) { const auto finish = [=](auto consumer) { _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { apply(ProcessMtpState(result)); consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).handleFloodErrors().send(); }; const auto sendMTPaccountUpdatePasswordSettings = [=]( const Core::CloudPasswordState &latestState, auto consumer) { const auto newPasswordBytes = newPassword.toUtf8(); const auto newPasswordHash = Core::ComputeCloudPasswordDigest( latestState.mtp.newPassword, bytes::make_span(newPasswordBytes)); if (!newPassword.isEmpty() && newPasswordHash.modpow.empty()) { consumer.put_error("INTERNAL_SERVER_ERROR"); return; } using Flag = MTPDaccount_passwordInputSettings::Flag; const auto flags = Flag::f_new_algo | Flag::f_new_password_hash | Flag::f_hint; const auto settings = MTP_account_passwordInputSettings( MTP_flags(flags), Core::PrepareCloudPasswordAlgo(newPassword.isEmpty() ? v::null : latestState.mtp.newPassword), newPassword.isEmpty() ? MTP_bytes() : MTP_bytes(newPasswordHash.modpow), MTP_string(newHint), MTP_string(), MTPSecureSecretSettings()); _api.request(MTPauth_RecoverPassword( MTP_flags(newPassword.isEmpty() ? MTPauth_RecoverPassword::Flags(0) : MTPauth_RecoverPassword::Flag::f_new_settings), MTP_string(code), settings )).done([=](const MTPauth_Authorization &result) { finish(consumer); }).fail([=](const MTP::Error &error) { const auto &type = error.type(); consumer.put_error_copy(type); }).handleFloodErrors().send(); }; return [=](auto consumer) { _api.request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { const auto latestState = ProcessMtpState(result); sendMTPaccountUpdatePasswordSettings(latestState, consumer); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return rpl::lifetime(); }; } rpl::producer CloudPassword::requestPasswordRecovery() { return [=](auto consumer) { _api.request(MTPauth_RequestPasswordRecovery( )).done([=](const MTPauth_PasswordRecovery &result) { result.match([&](const MTPDauth_passwordRecovery &data) { consumer.put_next(qs(data.vemail_pattern().v)); }); consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return rpl::lifetime(); }; } auto CloudPassword::checkRecoveryEmailAddressCode(const QString &code) -> rpl::producer { return [=](auto consumer) { _api.request(MTPauth_CheckRecoveryPassword( MTP_string(code) )).done([=] { consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).handleFloodErrors().send(); return rpl::lifetime(); }; } void RequestLoginEmailCode( MTP::Sender &api, const QString &sendToEmail, Fn done, Fn fail) { api.request(MTPaccount_SendVerifyEmailCode( MTP_emailVerifyPurposeLoginChange(), MTP_string(sendToEmail) )).done([=](const MTPaccount_SentEmailCode &result) { done(result.data().vlength().v, qs(result.data().vemail_pattern())); }).fail([=](const MTP::Error &error) { fail(error.type()); }).send(); } void VerifyLoginEmail( MTP::Sender &api, const QString &code, Fn done, Fn fail) { api.request(MTPaccount_VerifyEmail( MTP_emailVerifyPurposeLoginChange(), MTP_emailVerificationCode(MTP_string(code)) )).done([=](const MTPaccount_EmailVerified &result) { result.match([=](const MTPDaccount_emailVerified &data) { done(); }, [=](const MTPDaccount_emailVerifiedLogin &data) { fail(QString()); }); }).fail([=](const MTP::Error &error) { fail(error.type()); }).send(); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_cloud_password.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "mtproto/sender.h" namespace Core { struct CloudPasswordState; } // namespace Core class ApiWrap; namespace Main { class Session; } // namespace Main namespace Api { class CloudPassword final { public: struct SetOk { int unconfirmedEmailLengthCode = 0; }; using ResetRetryDate = int; explicit CloudPassword(not_null api); void reload(); void clearUnconfirmedPassword(); rpl::producer state() const; std::optional stateCurrent() const; rpl::producer resetPassword(); rpl::producer cancelResetPassword(); rpl::producer set( const QString &oldPassword, const QString &newPassword, const QString &hint, bool hasRecoveryEmail, const QString &recoveryEmail); rpl::producer check(const QString &password); rpl::producer confirmEmail(const QString &code); rpl::producer resendEmailCode(); rpl::producer setEmail( const QString &oldPassword, const QString &recoveryEmail); rpl::producer recoverPassword( const QString &code, const QString &newPassword, const QString &newHint); rpl::producer requestPasswordRecovery(); rpl::producer checkRecoveryEmailAddressCode( const QString &code); private: void apply(Core::CloudPasswordState state); MTP::Sender _api; mtpRequestId _requestId = 0; std::unique_ptr _state; rpl::event_stream _stateChanges; }; void RequestLoginEmailCode( MTP::Sender &api, const QString &sendToEmail, Fn done, Fn fail); void VerifyLoginEmail( MTP::Sender &api, const QString &code, Fn done, Fn fail); } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_common.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_common.h" #include "base/qt/qt_key_modifiers.h" #include "data/data_histories.h" #include "data/data_thread.h" #include "history/history.h" namespace Api { MTPSuggestedPost SuggestToMTP(SuggestOptions suggest) { using Flag = MTPDsuggestedPost::Flag; return suggest.exists ? MTP_suggestedPost( MTP_flags((suggest.date ? Flag::f_schedule_date : Flag()) | (suggest.price().empty() ? Flag() : Flag::f_price)), StarsAmountToTL(suggest.price()), MTP_int(suggest.date)) : MTPSuggestedPost(); } SendAction::SendAction( not_null thread, SendOptions options) : history(thread->owningHistory()) , options(options) , replyTo({ .messageId = { history->peer->id, thread->topicRootId() } }) { replyTo.topicRootId = replyTo.messageId.msg; } SendOptions DefaultSendWhenOnlineOptions() { return { .scheduled = kScheduledUntilOnlineTimestamp, .silent = base::IsCtrlPressed(), }; } MTPInputReplyTo SendAction::mtpReplyTo() const { return Data::ReplyToForMTP(history, replyTo); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_common.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "data/data_drafts.h" class History; namespace Data { class Thread; } // namespace Data namespace Api { inline constexpr auto kScheduledUntilOnlineTimestamp = TimeId(0x7FFFFFFE); [[nodiscard]] MTPSuggestedPost SuggestToMTP(SuggestOptions suggest); struct SendOptions { uint64 price = 0; PeerData *sendAs = nullptr; TimeId scheduled = 0; TimeId scheduleRepeatPeriod = 0; BusinessShortcutId shortcutId = 0; EffectId effectId = 0; QByteArray stakeSeedHash; int64 stakeNanoTon = 0; int starsApproved = 0; bool silent = false; bool handleSupportSwitch = false; bool invertCaption = false; bool hideViaBot = false; bool mediaSpoiler = false; crl::time ttlSeconds = 0; SuggestOptions suggest; friend inline bool operator==( const SendOptions &, const SendOptions &) = default; }; [[nodiscard]] SendOptions DefaultSendWhenOnlineOptions(); enum class SendType { Normal, Scheduled, ScheduledToUser, // For "Send when online". }; struct SendAction { explicit SendAction( not_null thread, SendOptions options = SendOptions()); not_null history; SendOptions options; FullReplyTo replyTo; bool clearDraft = true; bool generateLocal = true; MsgId replaceMediaOf = 0; [[nodiscard]] MTPInputReplyTo mtpReplyTo() const; friend inline bool operator==( const SendAction &, const SendAction &) = default; }; struct MessageToSend { explicit MessageToSend(SendAction action) : action(action) { } SendAction action; TextWithTags textWithTags; Data::WebPageDraft webPage; }; struct RemoteFileInfo { MTPInputFile file; std::optional thumb; std::optional videoCover; std::vector attachedStickers; bool forceFile = false; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_compose_with_ai.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_compose_with_ai.h" #include "api/api_text_entities.h" #include "apiwrap.h" namespace Api { namespace { [[nodiscard]] MTPTextWithEntities Serialize( not_null session, const TextWithEntities &text) { return MTP_textWithEntities( MTP_string(text.text), EntitiesToMTP(session, text.entities, ConvertOption::SkipLocal)); } } // namespace ComposeWithAi::ComposeWithAi(not_null api) : _session(&api->session()) , _api(&api->instance()) { } mtpRequestId ComposeWithAi::request( Request request, Fn done, Fn fail) { using Flag = MTPmessages_composeMessageWithAI::Flag; auto flags = MTPmessages_composeMessageWithAI::Flags(0); if (request.proofread) { flags |= Flag::f_proofread; } if (!request.translateToLang.isEmpty()) { flags |= Flag::f_translate_to_lang; } if (!request.changeTone.isEmpty()) { flags |= Flag::f_change_tone; } if (request.emojify) { flags |= Flag::f_emojify; } const auto session = _session; return _api.request(MTPmessages_ComposeMessageWithAI( MTP_flags(flags), Serialize(session, request.text), request.translateToLang.isEmpty() ? MTPstring() : MTP_string(request.translateToLang), request.changeTone.isEmpty() ? MTPstring() : MTP_string(request.changeTone) )).done([=, done = std::move(done)]( const MTPmessages_ComposedMessageWithAI &result) mutable { const auto &data = result.data(); auto parsed = Result{ .resultText = ParseTextWithEntities(session, data.vresult_text()), }; if (const auto diff = data.vdiff_text()) { parsed.diffText = ParseDiff(session, *diff); } done(std::move(parsed)); }).fail([=, fail = std::move(fail)](const MTP::Error &error) mutable { if (fail) { fail(error); } }).send(); } void ComposeWithAi::cancel(mtpRequestId requestId) { if (requestId) { _api.request(requestId).cancel(); } } ComposeWithAi::Diff ComposeWithAi::ParseDiff( not_null session, const MTPTextWithEntities &text) { const auto &data = text.data(); auto result = Diff{ .text = ParseTextWithEntities(session, text), }; const auto &entities = data.ventities().v; result.entities.reserve(entities.size()); for (const auto &entity : entities) { entity.match([&](const MTPDmessageEntityDiffInsert &data) { result.entities.push_back({ .type = DiffEntity::Type::Insert, .offset = data.voffset().v, .length = data.vlength().v, }); }, [&](const MTPDmessageEntityDiffReplace &data) { result.entities.push_back({ .type = DiffEntity::Type::Replace, .offset = data.voffset().v, .length = data.vlength().v, .oldText = qs(data.vold_text()), }); }, [&](const MTPDmessageEntityDiffDelete &data) { result.entities.push_back({ .type = DiffEntity::Type::Delete, .offset = data.voffset().v, .length = data.vlength().v, }); }, [](const auto &) { }); } return result; } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_compose_with_ai.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "mtproto/sender.h" #include "ui/text/text_entity.h" #include #include class ApiWrap; namespace Main { class Session; } // namespace Main namespace Api { class ComposeWithAi final { public: struct Request { TextWithEntities text; QString translateToLang; QString changeTone; bool proofread = false; bool emojify = false; }; struct DiffEntity { enum class Type { Insert, Replace, Delete, }; Type type = Type::Insert; int offset = 0; int length = 0; QString oldText; }; struct Diff { TextWithEntities text; std::vector entities; }; struct Result { TextWithEntities resultText; std::optional diffText; }; explicit ComposeWithAi(not_null api); [[nodiscard]] mtpRequestId request( Request request, Fn done, Fn fail = nullptr); void cancel(mtpRequestId requestId); private: [[nodiscard]] static Diff ParseDiff( not_null session, const MTPTextWithEntities &text); const not_null _session; MTP::Sender _api; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_confirm_phone.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_confirm_phone.h" #include "apiwrap.h" #include "lang/lang_keys.h" #include "main/main_account.h" #include "main/main_session.h" #include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_phone_box.h" #include "ui/text/format_values.h" // Ui::FormatPhone #include "window/window_session_controller.h" namespace Api { ConfirmPhone::ConfirmPhone(not_null api) : _api(&api->instance()) { } void ConfirmPhone::resolve( not_null controller, const QString &phone, const QString &hash) { if (_sendRequestId) { return; } _sendRequestId = _api.request(MTPaccount_SendConfirmPhoneCode( MTP_string(hash), MTP_codeSettings( MTP_flags(0), MTPVector(), MTPstring(), MTPBool()) )).done([=](const MTPauth_SentCode &result) { _sendRequestId = 0; result.match([&](const MTPDauth_sentCode &data) { const auto bad = [](const char *type) { LOG(("API Error: Should not be '%1'.").arg(type)); return 0; }; const auto sentCodeLength = data.vtype().match([&]( const MTPDauth_sentCodeTypeApp &data) { LOG(("Error: should not be in-app code!")); return 0; }, [&](const MTPDauth_sentCodeTypeSms &data) { return data.vlength().v; }, [&](const MTPDauth_sentCodeTypeFragmentSms &data) { return data.vlength().v; }, [&](const MTPDauth_sentCodeTypeCall &data) { return data.vlength().v; }, [&](const MTPDauth_sentCodeTypeFlashCall &) { return bad("FlashCall"); }, [&](const MTPDauth_sentCodeTypeMissedCall &) { return bad("MissedCall"); }, [&](const MTPDauth_sentCodeTypeFirebaseSms &) { return bad("FirebaseSms"); }, [&](const MTPDauth_sentCodeTypeEmailCode &) { return bad("EmailCode"); }, [&](const MTPDauth_sentCodeTypeSmsWord &) { return bad("SmsWord"); }, [&](const MTPDauth_sentCodeTypeSmsPhrase &) { return bad("SmsPhrase"); }, [&](const MTPDauth_sentCodeTypeSetUpEmailRequired &) { return bad("SetUpEmailRequired"); }); const auto fragmentUrl = data.vtype().match([]( const MTPDauth_sentCodeTypeFragmentSms &data) { return qs(data.vurl()); }, [](const auto &) { return QString(); }); const auto phoneHash = qs(data.vphone_code_hash()); const auto timeout = [&]() -> std::optional { if (const auto nextType = data.vnext_type()) { if (nextType->type() == mtpc_auth_codeTypeCall) { return data.vtimeout().value_or(60); } } return std::nullopt; }(); auto box = Box( phone, sentCodeLength, fragmentUrl, timeout); const auto boxWeak = base::make_weak(box.data()); using LoginCode = rpl::event_stream; const auto codeHandles = box->lifetime().make_state(); controller->session().account().setHandleLoginCode([=]( const QString &code) { codeHandles->fire_copy(code); }); box->resendRequests( ) | rpl::on_next([=] { _api.request(MTPauth_ResendCode( MTP_flags(0), MTP_string(phone), MTP_string(phoneHash), MTPstring() // reason )).done([=] { if (boxWeak) { boxWeak->callDone(); } }).send(); }, box->lifetime()); rpl::merge( codeHandles->events(), box->checkRequests() ) | rpl::on_next([=](const QString &code) { if (_checkRequestId) { return; } _checkRequestId = _api.request(MTPaccount_ConfirmPhone( MTP_string(phoneHash), MTP_string(code) )).done([=] { _checkRequestId = 0; controller->show( Ui::MakeInformBox( tr::lng_confirm_phone_success( tr::now, lt_phone, Ui::FormatPhone(phone))), Ui::LayerOption::CloseOther); }).fail([=](const MTP::Error &error) { _checkRequestId = 0; if (!boxWeak) { return; } const auto errorText = MTP::IsFloodError(error) ? tr::lng_flood_error(tr::now) : (error.type() == (u"PHONE_CODE_EMPTY"_q) || error.type() == (u"PHONE_CODE_INVALID"_q)) ? tr::lng_bad_code(tr::now) : Lang::Hard::ServerError(); boxWeak->showServerError(errorText); }).handleFloodErrors().send(); }, box->lifetime()); box->boxClosing( ) | rpl::on_next([=] { controller->session().account().setHandleLoginCode(nullptr); }, box->lifetime()); controller->show(std::move(box), Ui::LayerOption::CloseOther); }, [](const MTPDauth_sentCodeSuccess &) { LOG(("API Error: Unexpected auth.sentCodeSuccess " "(Api::ConfirmPhone).")); }, [](const MTPDauth_sentCodePaymentRequired &) { LOG(("API Error: Unexpected auth.sentCodePaymentRequired " "(Api::ConfirmPhone).")); }); }).fail([=](const MTP::Error &error) { _sendRequestId = 0; _checkRequestId = 0; const auto errorText = MTP::IsFloodError(error) ? tr::lng_flood_error(tr::now) : (error.code() == 400) ? tr::lng_confirm_phone_link_invalid(tr::now) : Lang::Hard::ServerError(); controller->show( Ui::MakeInformBox(errorText), Ui::LayerOption::CloseOther); }).handleFloodErrors().send(); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_confirm_phone.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "mtproto/sender.h" class ApiWrap; namespace Window { class SessionController; } // namespace Window namespace Api { class ConfirmPhone final { public: explicit ConfirmPhone(not_null api); void resolve( not_null controller, const QString &phone, const QString &hash); private: MTP::Sender _api; mtpRequestId _sendRequestId = 0; mtpRequestId _checkRequestId = 0; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_credits.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_credits.h" #include "api/api_credits_history_entry.h" #include "api/api_premium.h" #include "api/api_statistics_data_deserialize.h" #include "api/api_updates.h" #include "apiwrap.h" #include "base/unixtime.h" #include "data/components/credits.h" #include "data/data_channel.h" #include "data/data_document.h" #include "data/data_peer.h" #include "data/data_photo.h" #include "data/data_session.h" #include "data/data_user.h" #include "main/main_app_config.h" #include "main/main_session.h" namespace Api { namespace { constexpr auto kTransactionsLimit = 100; [[nodiscard]] Data::SubscriptionEntry SubscriptionFromTL( const MTPStarsSubscription &tl, not_null peer) { return Data::SubscriptionEntry{ .id = qs(tl.data().vid()), .inviteHash = qs(tl.data().vchat_invite_hash().value_or_empty()), .title = qs(tl.data().vtitle().value_or_empty()), .slug = qs(tl.data().vinvoice_slug().value_or_empty()), .until = base::unixtime::parse(tl.data().vuntil_date().v), .subscription = Data::PeerSubscription{ .credits = tl.data().vpricing().data().vamount().v, .period = tl.data().vpricing().data().vperiod().v, }, .barePeerId = peerFromMTP(tl.data().vpeer()).value, .photoId = (tl.data().vphoto() ? peer->owner().photoFromWeb( *tl.data().vphoto(), ImageLocation())->id : 0), .cancelled = tl.data().is_canceled(), .cancelledByBot = tl.data().is_bot_canceled(), .expired = (base::unixtime::now() > tl.data().vuntil_date().v), .canRefulfill = tl.data().is_can_refulfill(), }; } [[nodiscard]] Data::CreditsStatusSlice StatusFromTL( const MTPpayments_StarsStatus &status, not_null peer) { const auto &data = status.data(); peer->owner().processUsers(data.vusers()); peer->owner().processChats(data.vchats()); auto entries = std::vector(); if (const auto history = data.vhistory()) { entries.reserve(history->v.size()); for (const auto &tl : history->v) { entries.push_back(CreditsHistoryEntryFromTL(tl, peer)); } } auto subscriptions = std::vector(); if (const auto history = data.vsubscriptions()) { subscriptions.reserve(history->v.size()); for (const auto &tl : history->v) { subscriptions.push_back(SubscriptionFromTL(tl, peer)); } } return Data::CreditsStatusSlice{ .list = std::move(entries), .subscriptions = std::move(subscriptions), .balance = CreditsAmountFromTL(status.data().vbalance()), .subscriptionsMissingBalance = status.data().vsubscriptions_missing_balance().value_or_empty(), .allLoaded = !status.data().vnext_offset().has_value() && !status.data().vsubscriptions_next_offset().has_value(), .token = qs(status.data().vnext_offset().value_or_empty()), .tokenSubscriptions = qs( status.data().vsubscriptions_next_offset().value_or_empty()), }; } } // namespace CreditsTopupOptions::CreditsTopupOptions(not_null peer) : _peer(peer) , _api(&peer->session().api().instance()) { } rpl::producer CreditsTopupOptions::request() { return [=](auto consumer) { auto lifetime = rpl::lifetime(); const auto giftBarePeerId = !_peer->isSelf() ? _peer->id.value : 0; const auto optionsFromTL = [giftBarePeerId](const auto &options) { return ranges::views::all( options ) | ranges::views::transform([=](const auto &option) { return Data::CreditTopupOption{ .credits = option.data().vstars().v, .product = qs( option.data().vstore_product().value_or_empty()), .currency = qs(option.data().vcurrency()), .amount = option.data().vamount().v, .extended = option.data().is_extended(), .giftBarePeerId = giftBarePeerId, }; }) | ranges::to_vector; }; const auto fail = [=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }; if (_peer->isSelf()) { using TLOption = MTPStarsTopupOption; _api.request(MTPpayments_GetStarsTopupOptions( )).done([=](const MTPVector &result) { _options = optionsFromTL(result.v); consumer.put_done(); }).fail(fail).send(); } else if (const auto user = _peer->asUser()) { using TLOption = MTPStarsGiftOption; _api.request(MTPpayments_GetStarsGiftOptions( MTP_flags(MTPpayments_GetStarsGiftOptions::Flag::f_user_id), user->inputUser() )).done([=](const MTPVector &result) { _options = optionsFromTL(result.v); consumer.put_done(); }).fail(fail).send(); } return lifetime; }; } Data::CreditTopupOptions CreditsTopupOptions::options() const { return _options; } CreditsStatus::CreditsStatus(not_null peer) : _peer(peer) , _api(&peer->session().api().instance()) { } void CreditsStatus::request( const Data::CreditsStatusSlice::OffsetToken &token, Fn done) { if (_requestId) { return; } using TLResult = MTPpayments_StarsStatus; _requestId = _api.request(MTPpayments_GetStarsStatus( MTP_flags(0), _peer->isSelf() ? MTP_inputPeerSelf() : _peer->input() )).done([=](const TLResult &result) { _requestId = 0; const auto &balance = result.data().vbalance(); _peer->session().credits().apply( _peer->id, CreditsAmountFromTL(balance)); if (const auto onstack = done) { onstack(StatusFromTL(result, _peer)); } }).fail([=] { _requestId = 0; if (const auto onstack = done) { onstack({}); } }).send(); } CreditsHistory::CreditsHistory( not_null peer, bool in, bool out, bool currency) : _peer(peer) , _flags(((in == out) ? HistoryTL::Flags(0) : HistoryTL::Flags(0) | (in ? HistoryTL::Flag::f_inbound : HistoryTL::Flags(0)) | (out ? HistoryTL::Flag::f_outbound : HistoryTL::Flags(0))) | (currency ? HistoryTL::Flag::f_ton : HistoryTL::Flags(0))) , _api(&peer->session().api().instance()) { } void CreditsHistory::request( const Data::CreditsStatusSlice::OffsetToken &token, Fn done) { if (_requestId) { return; } _requestId = _api.request(MTPpayments_GetStarsTransactions( MTP_flags(_flags), MTPstring(), // subscription_id _peer->isSelf() ? MTP_inputPeerSelf() : _peer->input(), MTP_string(token), MTP_int(kTransactionsLimit) )).done([=](const MTPpayments_StarsStatus &result) { _requestId = 0; done(StatusFromTL(result, _peer)); }).fail([=] { _requestId = 0; done({}); }).send(); } void CreditsHistory::requestSubscriptions( const Data::CreditsStatusSlice::OffsetToken &token, Fn done, bool missingBalance) { if (_requestId) { return; } _requestId = _api.request(MTPpayments_GetStarsSubscriptions( MTP_flags(missingBalance ? MTPpayments_getStarsSubscriptions::Flag::f_missing_balance : MTPpayments_getStarsSubscriptions::Flags(0)), _peer->isSelf() ? MTP_inputPeerSelf() : _peer->input(), MTP_string(token) )).done([=](const MTPpayments_StarsStatus &result) { _requestId = 0; done(StatusFromTL(result, _peer)); }).fail([=] { _requestId = 0; done({}); }).send(); } rpl::producer> PremiumPeerBot( not_null session) { const auto username = session->appConfig().get( u"premium_bot_username"_q, QString()); if (username.isEmpty()) { return rpl::never>(); } if (const auto p = session->data().peerByUsername(username)) { return rpl::single>(p); } return [=](auto consumer) { auto lifetime = rpl::lifetime(); const auto api = lifetime.make_state(&session->mtp()); api->request(MTPcontacts_ResolveUsername( MTP_flags(0), MTP_string(username), MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { session->data().processUsers(result.data().vusers()); session->data().processChats(result.data().vchats()); const auto botPeer = session->data().peerLoaded( peerFromMTP(result.data().vpeer())); if (!botPeer) { return consumer.put_done(); } consumer.put_next(not_null{ botPeer }); }).send(); return lifetime; }; } CreditsEarnStatistics::CreditsEarnStatistics(not_null peer) : StatisticsRequestSender(peer) , _isUser(peer->isUser()) { } rpl::producer CreditsEarnStatistics::request() { return [=](auto consumer) { auto lifetime = rpl::lifetime(); const auto finish = [=](const QString &url) { api().request(MTPpayments_GetStarsRevenueStats( MTP_flags(0), (_isUser ? user()->input() : channel()->input()) )).done([=](const MTPpayments_StarsRevenueStats &result) { const auto &data = result.data(); const auto &status = data.vstatus().data(); _data = Data::CreditsEarnStatistics{ .revenueGraph = StatisticalGraphFromTL( data.vrevenue_graph()), .currentBalance = CreditsAmountFromTL( status.vcurrent_balance()), .availableBalance = CreditsAmountFromTL( status.vavailable_balance()), .overallRevenue = CreditsAmountFromTL( status.voverall_revenue()), .usdRate = data.vusd_rate().v, .isWithdrawalEnabled = status.is_withdrawal_enabled(), .nextWithdrawalAt = status.vnext_withdrawal_at() ? base::unixtime::parse( status.vnext_withdrawal_at()->v) : QDateTime(), .buyAdsUrl = url, }; consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); }; api().request( MTPpayments_GetStarsRevenueAdsAccountUrl( (_isUser ? user()->input() : channel()->input())) ).done([=](const MTPpayments_StarsRevenueAdsAccountUrl &result) { finish(qs(result.data().vurl())); }).fail([=](const MTP::Error &error) { finish({}); }).send(); return lifetime; }; } Data::CreditsEarnStatistics CreditsEarnStatistics::data() const { return _data; } CreditsGiveawayOptions::CreditsGiveawayOptions(not_null peer) : _peer(peer) , _api(&peer->session().api().instance()) { } rpl::producer CreditsGiveawayOptions::request() { return [=](auto consumer) { auto lifetime = rpl::lifetime(); using TLOption = MTPStarsGiveawayOption; const auto optionsFromTL = [=](const auto &options) { return ranges::views::all( options ) | ranges::views::transform([=](const auto &option) { return Data::CreditsGiveawayOption{ .winners = ranges::views::all( option.data().vwinners().v ) | ranges::views::transform([](const auto &winner) { return Data::CreditsGiveawayOption::Winner{ .users = winner.data().vusers().v, .perUserStars = winner.data().vper_user_stars().v, .isDefault = winner.data().is_default(), }; }) | ranges::to_vector, .storeProduct = qs( option.data().vstore_product().value_or_empty()), .currency = qs(option.data().vcurrency()), .amount = option.data().vamount().v, .credits = option.data().vstars().v, .yearlyBoosts = option.data().vyearly_boosts().v, .isExtended = option.data().is_extended(), .isDefault = option.data().is_default(), }; }) | ranges::to_vector; }; const auto fail = [=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }; _api.request(MTPpayments_GetStarsGiveawayOptions( )).done([=](const MTPVector &result) { _options = optionsFromTL(result.v); consumer.put_done(); }).fail(fail).send(); return lifetime; }; } Data::CreditsGiveawayOptions CreditsGiveawayOptions::options() const { return _options; } void EditCreditsSubscription( not_null session, const QString &id, bool cancel, Fn done, Fn fail) { using Flag = MTPpayments_ChangeStarsSubscription::Flag; session->api().request( MTPpayments_ChangeStarsSubscription( MTP_flags(Flag::f_canceled), MTP_inputPeerSelf(), MTP_string(id), MTP_bool(cancel) )).done(done).fail([=](const MTP::Error &e) { fail(e.type()); }).send(); } MTPInputSavedStarGift InputSavedStarGiftId( const Data::SavedStarGiftId &id, const std::shared_ptr &unique) { return (!id && unique) ? MTP_inputSavedStarGiftSlug(MTP_string(unique->slug)) : id.isUser() ? MTP_inputSavedStarGiftUser(MTP_int(id.userMessageId().bare)) : MTP_inputSavedStarGiftChat( id.chat()->input(), MTP_long(id.chatSavedId())); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_credits.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "api/api_statistics_sender.h" #include "data/data_credits.h" #include "data/data_credits_earn.h" #include "mtproto/sender.h" namespace Data { class SavedStarGiftId; } // namespace Data namespace Main { class Session; } // namespace Main class UserData; namespace Api { class CreditsTopupOptions final { public: CreditsTopupOptions(not_null peer); [[nodiscard]] rpl::producer request(); [[nodiscard]] Data::CreditTopupOptions options() const; private: const not_null _peer; Data::CreditTopupOptions _options; MTP::Sender _api; }; class CreditsGiveawayOptions final { public: CreditsGiveawayOptions(not_null peer); [[nodiscard]] rpl::producer request(); [[nodiscard]] Data::CreditsGiveawayOptions options() const; private: const not_null _peer; Data::CreditsGiveawayOptions _options; MTP::Sender _api; }; class CreditsStatus final { public: CreditsStatus(not_null peer); void request( const Data::CreditsStatusSlice::OffsetToken &token, Fn done); private: const not_null _peer; mtpRequestId _requestId = 0; MTP::Sender _api; }; class CreditsHistory final { public: CreditsHistory( not_null peer, bool in, bool out, bool currency = false); void request( const Data::CreditsStatusSlice::OffsetToken &token, Fn done); void requestSubscriptions( const Data::CreditsStatusSlice::OffsetToken &token, Fn done, bool missingBalance = false); private: using HistoryTL = MTPpayments_GetStarsTransactions; const not_null _peer; const HistoryTL::Flags _flags; mtpRequestId _requestId = 0; MTP::Sender _api; }; class CreditsEarnStatistics final : public StatisticsRequestSender { public: explicit CreditsEarnStatistics(not_null); [[nodiscard]] rpl::producer request(); [[nodiscard]] Data::CreditsEarnStatistics data() const; private: const bool _isUser = false; Data::CreditsEarnStatistics _data; }; [[nodiscard]] rpl::producer> PremiumPeerBot( not_null session); void EditCreditsSubscription( not_null session, const QString &id, bool cancel, Fn done, Fn fail); [[nodiscard]] MTPInputSavedStarGift InputSavedStarGiftId( const Data::SavedStarGiftId &id, const std::shared_ptr &unique = nullptr); } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_credits_history_entry.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_credits_history_entry.h" #include "api/api_premium.h" #include "base/unixtime.h" #include "data/data_channel.h" #include "data/data_credits.h" #include "data/data_document.h" #include "data/data_peer.h" #include "data/data_photo.h" #include "data/data_session.h" #include "data/data_user.h" #include "main/main_session.h" namespace Api { Data::CreditsHistoryEntry CreditsHistoryEntryFromTL( const MTPStarsTransaction &tl, not_null peer) { using HistoryPeerTL = MTPDstarsTransactionPeer; using namespace Data; const auto owner = &peer->owner(); const auto photo = tl.data().vphoto() ? owner->photoFromWeb(*tl.data().vphoto(), ImageLocation()) : nullptr; auto extended = std::vector(); if (const auto list = tl.data().vextended_media()) { extended.reserve(list->v.size()); for (const auto &media : list->v) { media.match([&](const MTPDmessageMediaPhoto &data) { if (const auto inner = data.vphoto()) { const auto photo = owner->processPhoto(*inner); if (!photo->isNull()) { extended.push_back(CreditsHistoryMedia{ .type = CreditsHistoryMediaType::Photo, .id = photo->id, }); } } }, [&](const MTPDmessageMediaDocument &data) { if (const auto inner = data.vdocument()) { const auto document = owner->processDocument( *inner, data.valt_documents()); if (document->isAnimation() || document->isVideoFile() || document->isGifv()) { extended.push_back(CreditsHistoryMedia{ .type = CreditsHistoryMediaType::Video, .id = document->id, }); } } }, [&](const auto &) {}); } } const auto barePeerId = tl.data().vpeer().match([]( const HistoryPeerTL &p) { return peerFromMTP(p.vpeer()); }, [](const auto &) { return PeerId(0); }).value; const auto stargift = tl.data().vstargift(); const auto nonUniqueGift = stargift ? stargift->match([&](const MTPDstarGift &data) { return &data; }, [](const auto &) { return (const MTPDstarGift*)nullptr; }) : nullptr; const auto reaction = tl.data().is_reaction(); const auto amount = CreditsAmountFromTL(tl.data().vamount()); const auto starrefAmount = CreditsAmountFromTL( tl.data().vstarref_amount()); const auto starrefCommission = tl.data().vstarref_commission_permille().value_or_empty(); const auto starrefBarePeerId = tl.data().vstarref_peer() ? peerFromMTP(*tl.data().vstarref_peer()).value : 0; const auto incoming = (amount >= CreditsAmount()); const auto paidMessagesCount = tl.data().vpaid_messages().value_or_empty(); const auto premiumMonthsForStars = tl.data().vpremium_gift_months().value_or_empty(); const auto saveActorId = (reaction || !extended.empty() || paidMessagesCount) && incoming; const auto parsedGift = stargift ? FromTL(&peer->session(), *stargift) : std::optional(); const auto giftStickerId = parsedGift ? parsedGift->document->id : 0; return Data::CreditsHistoryEntry{ .id = qs(tl.data().vid()), .title = qs(tl.data().vtitle().value_or_empty()), .description = { qs(tl.data().vdescription().value_or_empty()) }, .date = base::unixtime::parse( tl.data().vads_proceeds_from_date().value_or( tl.data().vdate().v)), .photoId = photo ? photo->id : 0, .extended = std::move(extended), .credits = CreditsAmountFromTL(tl.data().vamount()), .bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()), .barePeerId = saveActorId ? peer->id.value : barePeerId, .bareGiveawayMsgId = uint64( tl.data().vgiveaway_post_id().value_or_empty()), .bareGiftStickerId = giftStickerId, .bareActorId = saveActorId ? barePeerId : uint64(0), .uniqueGift = parsedGift ? parsedGift->unique : nullptr, .starrefAmount = paidMessagesCount ? CreditsAmount() : starrefAmount, .starrefCommission = paidMessagesCount ? 0 : starrefCommission, .starrefRecipientId = paidMessagesCount ? 0 : starrefBarePeerId, .peerType = tl.data().vpeer().match([](const HistoryPeerTL &) { return Data::CreditsHistoryEntry::PeerType::Peer; }, [](const MTPDstarsTransactionPeerPlayMarket &) { return Data::CreditsHistoryEntry::PeerType::PlayMarket; }, [](const MTPDstarsTransactionPeerFragment &) { return Data::CreditsHistoryEntry::PeerType::Fragment; }, [](const MTPDstarsTransactionPeerAppStore &) { return Data::CreditsHistoryEntry::PeerType::AppStore; }, [](const MTPDstarsTransactionPeerUnsupported &) { return Data::CreditsHistoryEntry::PeerType::Unsupported; }, [](const MTPDstarsTransactionPeerPremiumBot &) { return Data::CreditsHistoryEntry::PeerType::PremiumBot; }, [](const MTPDstarsTransactionPeerAds &) { return Data::CreditsHistoryEntry::PeerType::Ads; }, [](const MTPDstarsTransactionPeerAPI &) { return Data::CreditsHistoryEntry::PeerType::API; }), .subscriptionUntil = tl.data().vsubscription_period() ? base::unixtime::parse(base::unixtime::now() + tl.data().vsubscription_period()->v) : QDateTime(), .adsProceedsToDate = tl.data().vads_proceeds_to_date() ? base::unixtime::parse(tl.data().vads_proceeds_to_date()->v) : QDateTime(), .successDate = tl.data().vtransaction_date() ? base::unixtime::parse(tl.data().vtransaction_date()->v) : QDateTime(), .successLink = qs(tl.data().vtransaction_url().value_or_empty()), .paidMessagesCount = paidMessagesCount, .paidMessagesAmount = (paidMessagesCount ? starrefAmount : CreditsAmount()), .paidMessagesCommission = paidMessagesCount ? starrefCommission : 0, .limitedCount = parsedGift ? parsedGift->limitedCount : 0, .limitedLeft = parsedGift ? parsedGift->limitedLeft : 0, .starsConverted = int(nonUniqueGift ? nonUniqueGift->vconvert_stars().v : 0), .premiumMonthsForStars = premiumMonthsForStars, .floodSkip = int(tl.data().vfloodskip_number().value_or(0)), .converted = stargift && incoming, .stargift = stargift.has_value(), .postsSearch = tl.data().is_posts_search(), .giftUpgraded = tl.data().is_stargift_upgrade(), .giftResale = tl.data().is_stargift_resale(), .reaction = tl.data().is_reaction(), .refunded = tl.data().is_refund(), .pending = tl.data().is_pending(), .failed = tl.data().is_failed(), .in = incoming, .gift = tl.data().is_gift() || stargift.has_value(), }; } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_credits_history_entry.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once class PeerData; namespace Data { struct CreditsHistoryEntry; } // namespace Data namespace Api { [[nodiscard]] Data::CreditsHistoryEntry CreditsHistoryEntryFromTL( const MTPStarsTransaction &tl, not_null peer); } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_earn.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_earn.h" #include "api/api_cloud_password.h" #include "apiwrap.h" #include "ui/layers/generic_box.h" #include "boxes/passcode_box.h" #include "data/data_channel.h" #include "data/data_session.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "ui/basic_click_handlers.h" #include "ui/widgets/buttons.h" namespace Api { void RestrictSponsored( not_null channel, bool restricted, Fn failed) { channel->session().api().request(MTPchannels_RestrictSponsoredMessages( channel->inputChannel(), MTP_bool(restricted)) ).done([=](const MTPUpdates &updates) { channel->session().api().applyUpdates(updates); }).fail([=](const MTP::Error &error) { failed(error.type()); }).send(); } void HandleWithdrawalButton( RewardReceiver receiver, not_null button, std::shared_ptr show) { Expects(receiver.currencyReceiver || (receiver.creditsReceiver && receiver.creditsAmount)); struct State { rpl::lifetime lifetime; bool loading = false; }; const auto currencyReceiver = receiver.currencyReceiver; const auto creditsReceiver = receiver.creditsReceiver; const auto isChannel = receiver.currencyReceiver && receiver.currencyReceiver->isChannel(); const auto state = button->lifetime().make_state(); const auto session = (currencyReceiver ? ¤cyReceiver->session() : &creditsReceiver->session()); using CreditsOutUrl = MTPpayments_StarsRevenueWithdrawalUrl; session->api().cloudPassword().reload(); const auto processOut = [=] { if (state->loading) { return; } else if (creditsReceiver && !receiver.creditsAmount()) { return; } state->loading = true; state->lifetime = session->api().cloudPassword().state( ) | rpl::take( 1 ) | rpl::on_next([=](const Core::CloudPasswordState &pass) { state->loading = false; auto fields = PasscodeBox::CloudFields::From(pass); fields.customTitle = isChannel ? tr::lng_channel_earn_balance_password_title() : tr::lng_bot_earn_balance_password_title(); fields.customDescription = isChannel ? tr::lng_channel_earn_balance_password_description(tr::now) : tr::lng_bot_earn_balance_password_description(tr::now); fields.customSubmitButton = tr::lng_passcode_submit(); fields.customCheckCallback = crl::guard(button, [=]( const Core::CloudPasswordResult &result, base::weak_qptr box) { const auto done = [=](const QString &result) { if (!result.isEmpty()) { UrlClickHandler::Open(result); if (box) { box->closeBox(); } } }; const auto fail = [=](const MTP::Error &error) { const auto message = error.type(); if (box && !box->handleCustomCheckError(message)) { show->showToast(message); } }; if (currencyReceiver || creditsReceiver) { using F = MTPpayments_getStarsRevenueWithdrawalUrl::Flag; session->api().request( MTPpayments_GetStarsRevenueWithdrawalUrl( MTP_flags(currencyReceiver ? F::f_ton : F::f_amount), currencyReceiver ? currencyReceiver->input() : creditsReceiver->input(), MTP_long(creditsReceiver ? receiver.creditsAmount() : 0), result.result )).done([=](const CreditsOutUrl &r) { done(qs(r.data().vurl())); }).fail(fail).send(); } }); show->show(Box(session, fields)); }); }; button->setClickedCallback([=] { if (state->loading) { return; } const auto fail = [=](const MTP::Error &error) { auto box = PrePasswordErrorBox( error.type(), session, TextWithEntities{ tr::lng_channel_earn_out_check_password_about(tr::now), }); if (box) { show->show(std::move(box)); state->loading = false; } else { processOut(); } }; if (currencyReceiver || creditsReceiver) { using F = MTPpayments_getStarsRevenueWithdrawalUrl::Flag; session->api().request( MTPpayments_GetStarsRevenueWithdrawalUrl( MTP_flags(currencyReceiver ? F::f_ton : F::f_amount), currencyReceiver ? currencyReceiver->input() : creditsReceiver->input(), MTP_long(creditsReceiver ? receiver.creditsAmount() : 0), MTP_inputCheckPasswordEmpty() )).fail(fail).send(); } }); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_earn.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once class ChannelData; namespace Ui { class RippleButton; class Show; } // namespace Ui namespace Api { void RestrictSponsored( not_null channel, bool restricted, Fn failed); struct RewardReceiver final { PeerData *currencyReceiver = nullptr; PeerData *creditsReceiver = nullptr; Fn creditsAmount; }; void HandleWithdrawalButton( RewardReceiver receiver, not_null button, std::shared_ptr show); } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_editing.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_editing.h" #include "apiwrap.h" #include "api/api_media.h" #include "api/api_text_entities.h" #include "base/random.h" #include "ui/boxes/confirm_box.h" #include "data/business/data_shortcut_messages.h" #include "data/components/scheduled_messages.h" #include "data/data_file_origin.h" #include "data/data_histories.h" #include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_todo_list.h" #include "data/data_web_page.h" #include "history/view/controls/history_view_compose_media_edit_manager.h" #include "history/history.h" #include "history/history_item_components.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "mtproto/mtproto_response.h" #include "boxes/abstract_box.h" // Ui::show(). namespace Api { namespace { using namespace rpl::details; template constexpr auto WithId = is_callable_plain_v, mtpRequestId>; template constexpr auto WithoutId = is_callable_plain_v>; template constexpr auto WithoutCallback = is_callable_plain_v; template constexpr auto ErrorWithId = is_callable_plain_v; template constexpr auto ErrorWithoutId = is_callable_plain_v; template mtpRequestId SuggestMessage( not_null item, const TextWithEntities &textWithEntities, Data::WebPageDraft webpage, SendOptions options, DoneCallback &&done, FailCallback &&fail) { Expects(options.suggest.exists); Expects(!options.scheduled); const auto session = &item->history()->session(); const auto api = &session->api(); const auto thread = item->history()->amMonoforumAdmin() ? item->savedSublist() : (Data::Thread*)item->history(); auto action = SendAction(thread, options); action.replyTo = FullReplyTo{ .messageId = item->fullId(), .monoforumPeerId = (item->history()->amMonoforumAdmin() ? item->sublistPeerId() : PeerId()), }; auto message = MessageToSend(std::move(action)); message.textWithTags = TextWithTags{ textWithEntities.text, TextUtilities::ConvertEntitiesToTextTags(textWithEntities.entities) }; message.webPage = webpage; api->sendMessage(std::move(message)); const auto requestId = -1; crl::on_main(session, [=] { const auto type = u"MESSAGE_NOT_MODIFIED"_q; if constexpr (ErrorWithId) { fail(type, requestId); } else if constexpr (ErrorWithoutId) { fail(type); } else if constexpr (WithoutCallback) { fail(); } else { t_bad_callback(fail); } }); return requestId; } template mtpRequestId SuggestMedia( not_null item, const TextWithEntities &textWithEntities, Data::WebPageDraft webpage, SendOptions options, DoneCallback &&done, FailCallback &&fail, std::optional inputMedia) { Expects(options.suggest.exists); Expects(!options.scheduled); const auto session = &item->history()->session(); const auto api = &session->api(); const auto text = textWithEntities.text; const auto sentEntities = EntitiesToMTP( session, textWithEntities.entities, ConvertOption::SkipLocal); const auto updateRecentStickers = inputMedia ? Api::HasAttachedStickers(*inputMedia) : false; const auto emptyFlag = MTPmessages_SendMedia::Flag(0); auto replyTo = FullReplyTo{ .messageId = item->fullId(), .monoforumPeerId = (item->history()->amMonoforumAdmin() ? item->sublistPeerId() : PeerId()), }; const auto flags = emptyFlag | MTPmessages_SendMedia::Flag::f_reply_to | MTPmessages_SendMedia::Flag::f_suggested_post | (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert) || options.invertCaption) ? MTPmessages_SendMedia::Flag::f_invert_media : emptyFlag) | (!sentEntities.v.isEmpty() ? MTPmessages_SendMedia::Flag::f_entities : emptyFlag) | (options.starsApproved ? MTPmessages_SendMedia::Flag::f_allow_paid_stars : emptyFlag); const auto randomId = base::RandomValue(); return api->request(MTPmessages_SendMedia( MTP_flags(flags), item->history()->peer->input(), ReplyToForMTP(item->history(), replyTo), inputMedia.value_or(Data::WebPageForMTP(webpage, text.isEmpty())), MTP_string(text), MTP_long(randomId), MTPReplyMarkup(), sentEntities, MTPint(), // schedule_date MTPint(), // schedule_repeat_period MTPInputPeer(), // send_as MTPInputQuickReplyShortcut(), // quick_reply_shortcut MTPlong(), // effect MTP_long(options.starsApproved), Api::SuggestToMTP(options.suggest) )).done([=]( const MTPUpdates &result, [[maybe_unused]] mtpRequestId requestId) { const auto apply = [=] { api->applyUpdates(result); }; if constexpr (WithId) { done(apply, requestId); } else if constexpr (WithoutId) { done(apply); } else if constexpr (WithoutCallback) { done(); apply(); } else { t_bad_callback(done); } if (updateRecentStickers) { api->requestSpecialStickersForce(false, false, true); } }).fail([=](const MTP::Error &error, mtpRequestId requestId) { if constexpr (ErrorWithId) { fail(error.type(), requestId); } else if constexpr (ErrorWithoutId) { fail(error.type()); } else if constexpr (WithoutCallback) { fail(); } else { t_bad_callback(fail); } }).send(); } template mtpRequestId SuggestMessageOrMedia( not_null item, const TextWithEntities &textWithEntities, Data::WebPageDraft webpage, SendOptions options, DoneCallback &&done, FailCallback &&fail, std::optional inputMedia) { const auto wasMedia = item->media(); if (!inputMedia && wasMedia && wasMedia->allowsEditCaption()) { if (const auto photo = wasMedia->photo()) { inputMedia = MTP_inputMediaPhoto( MTP_flags(0), photo->mtpInput(), MTPint(), // ttl_seconds MTPInputDocument()); // video } else if (const auto document = wasMedia->document()) { inputMedia = MTP_inputMediaDocument( MTP_flags(0), document->mtpInput(), MTPInputPhoto(), // video_cover MTPint(), // video_timestamp MTPint(), // ttl_seconds MTPstring()); // query } } if (inputMedia) { return SuggestMedia( item, textWithEntities, webpage, options, std::move(done), std::move(fail), inputMedia); } return SuggestMessage( item, textWithEntities, webpage, options, std::move(done), std::move(fail)); } template mtpRequestId EditMessage( not_null item, const TextWithEntities &textWithEntities, Data::WebPageDraft webpage, SendOptions options, DoneCallback &&done, FailCallback &&fail, std::optional inputMedia = std::nullopt) { if (item->computeSuggestionActions() == SuggestionActions::AcceptAndDecline) { return SuggestMessageOrMedia( item, textWithEntities, webpage, options, std::move(done), std::move(fail), inputMedia); } const auto session = &item->history()->session(); const auto api = &session->api(); const auto text = textWithEntities.text; const auto sentEntities = EntitiesToMTP( session, textWithEntities.entities, ConvertOption::SkipLocal); const auto media = item->media(); const auto updateRecentStickers = inputMedia.has_value() ? Api::HasAttachedStickers(*inputMedia) : false; const auto emptyFlag = MTPmessages_EditMessage::Flag(0); const auto flags = emptyFlag | ((!text.isEmpty() || media) ? MTPmessages_EditMessage::Flag::f_message : emptyFlag) | ((media && inputMedia.has_value()) ? MTPmessages_EditMessage::Flag::f_media : emptyFlag) | (webpage.removed ? MTPmessages_EditMessage::Flag::f_no_webpage : emptyFlag) | ((!webpage.removed && !webpage.url.isEmpty()) ? MTPmessages_EditMessage::Flag::f_media : emptyFlag) | (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert) || options.invertCaption) ? MTPmessages_EditMessage::Flag::f_invert_media : emptyFlag) | (!sentEntities.v.isEmpty() ? MTPmessages_EditMessage::Flag::f_entities : emptyFlag) | (options.scheduled ? MTPmessages_EditMessage::Flag::f_schedule_date : emptyFlag) | ((options.scheduled && options.scheduleRepeatPeriod) ? MTPmessages_EditMessage::Flag::f_schedule_repeat_period : emptyFlag) | (item->isBusinessShortcut() ? MTPmessages_EditMessage::Flag::f_quick_reply_shortcut_id : emptyFlag); const auto id = item->isScheduled() ? session->scheduledMessages().lookupId(item) : item->isBusinessShortcut() ? session->data().shortcutMessages().lookupId(item) : item->id; return api->request(MTPmessages_EditMessage( MTP_flags(flags), item->history()->peer->input(), MTP_int(id), MTP_string(text), inputMedia.value_or(Data::WebPageForMTP(webpage, text.isEmpty())), MTPReplyMarkup(), sentEntities, MTP_int(options.scheduled), MTP_int(options.scheduleRepeatPeriod), MTP_int(item->shortcutId()) )).done([=]( const MTPUpdates &result, [[maybe_unused]] mtpRequestId requestId) { const auto apply = [=] { api->applyUpdates(result); }; if constexpr (WithId) { done(apply, requestId); } else if constexpr (WithoutId) { done(apply); } else if constexpr (WithoutCallback) { done(); apply(); } else { t_bad_callback(done); } if (updateRecentStickers) { api->requestSpecialStickersForce(false, false, true); } }).fail([=](const MTP::Error &error, mtpRequestId requestId) { if constexpr (ErrorWithId) { fail(error.type(), requestId); } else if constexpr (ErrorWithoutId) { fail(error.type()); } else if constexpr (WithoutCallback) { fail(); } else { t_bad_callback(fail); } }).send(); } template mtpRequestId EditMessage( not_null item, SendOptions options, DoneCallback &&done, FailCallback &&fail, std::optional inputMedia = std::nullopt) { const auto &text = item->originalText(); const auto webpage = (!item->media() || !item->media()->webpage()) ? Data::WebPageDraft{ .removed = true } : Data::WebPageDraft::FromItem(item); return EditMessage( item, text, webpage, options, std::forward(done), std::forward(fail), inputMedia); } void EditMessageWithUploadedMedia( not_null item, SendOptions options, MTPInputMedia media) { const auto done = [=](Fn applyUpdates) { if (item) { item->removeFromSharedMediaIndex(); item->clearSavedMedia(); item->setIsLocalUpdateMedia(true); applyUpdates(); item->setIsLocalUpdateMedia(false); } }; const auto fail = [=](const QString &error) { const auto session = &item->history()->session(); const auto notModified = (error == u"MESSAGE_NOT_MODIFIED"_q); const auto mediaInvalid = (error == u"MEDIA_NEW_INVALID"_q); if (notModified || mediaInvalid) { item->returnSavedMedia(); session->data().sendHistoryChangeNotifications(); if (mediaInvalid) { Ui::show( Ui::MakeInformBox(tr::lng_edit_media_invalid_file()), Ui::LayerOption::KeepOther); } } else { session->api().sendMessageFail(error, item->history()->peer); } }; EditMessage(item, options, done, fail, media); } } // namespace void RescheduleMessage( not_null item, SendOptions options) { const auto empty = [] {}; options.invertCaption = item->invertMedia(); EditMessage(item, options, empty, empty); } void EditMessageWithUploadedDocument( HistoryItem *item, RemoteFileInfo info, SendOptions options) { if (!item || !item->media() || !item->media()->document()) { return; } EditMessageWithUploadedMedia( item, options, PrepareUploadedDocument(item, std::move(info))); } void EditMessageWithUploadedPhoto( HistoryItem *item, RemoteFileInfo info, SendOptions options) { if (!item || !item->media() || !item->media()->photo()) { return; } EditMessageWithUploadedMedia( item, options, PrepareUploadedPhoto(item, std::move(info))); } mtpRequestId EditCaption( not_null item, const TextWithEntities &caption, SendOptions options, Fn done, Fn fail) { return EditMessage( item, caption, Data::WebPageDraft(), options, done, fail); } mtpRequestId EditTextMessage( not_null item, const TextWithEntities &caption, Data::WebPageDraft webpage, SendOptions options, Fn done, Fn fail, bool spoilered) { const auto media = item->media(); if (media && HistoryView::MediaEditManager::CanBeSpoilered(item) && spoilered != media->hasSpoiler()) { auto takeInputMedia = Fn()>(nullptr); auto takeFileReference = Fn(nullptr); if (const auto photo = media->photo()) { using Flag = MTPDinputMediaPhoto::Flag; const auto flags = Flag() | (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag()) | (spoilered ? Flag::f_spoiler : Flag()); takeInputMedia = [=] { return MTP_inputMediaPhoto( MTP_flags(flags), photo->mtpInput(), MTP_int(media->ttlSeconds()), MTPInputDocument()); // video }; takeFileReference = [=] { return photo->fileReference(); }; } else if (const auto document = media->document()) { using Flag = MTPDinputMediaDocument::Flag; const auto videoCover = media->videoCover(); const auto videoTimestamp = media->videoTimestamp(); const auto flags = Flag() | (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag()) | (spoilered ? Flag::f_spoiler : Flag()) | (videoTimestamp ? Flag::f_video_timestamp : Flag()) | (videoCover ? Flag::f_video_cover : Flag()); takeInputMedia = [=] { return MTP_inputMediaDocument( MTP_flags(flags), document->mtpInput(), (videoCover ? videoCover->mtpInput() : MTPInputPhoto()), MTP_int(media->ttlSeconds()), MTP_int(videoTimestamp), MTPstring()); // query }; takeFileReference = [=] { return document->fileReference(); }; } const auto usedFileReference = takeFileReference ? takeFileReference() : QByteArray(); const auto origin = item->fullId(); const auto api = &item->history()->session().api(); const auto performRequest = [=]( const auto &repeatRequest, mtpRequestId originalRequestId) -> mtpRequestId { const auto handleReference = [=]( const QString &error, mtpRequestId requestId) { if (error.startsWith(u"FILE_REFERENCE_"_q)) { api->refreshFileReference(origin, [=](const auto &) { if (takeFileReference && (takeFileReference() != usedFileReference)) { repeatRequest( repeatRequest, originalRequestId ? originalRequestId : requestId); } else { fail(error, requestId); } }); } else { fail(error, requestId); } }; const auto callback = [=]( Fn applyUpdates, mtpRequestId requestId) { applyUpdates(); done(originalRequestId ? originalRequestId : requestId); }; const auto requestId = EditMessage( item, caption, webpage, options, callback, handleReference, takeInputMedia ? takeInputMedia() : std::nullopt); return originalRequestId ? originalRequestId : requestId; }; return performRequest(performRequest, 0); } const auto callback = [=](Fn applyUpdates, mtpRequestId id) { applyUpdates(); done(id); }; return EditMessage( item, caption, webpage, options, callback, fail, std::nullopt); } void EditTodoList( not_null item, const TodoListData &data, SendOptions options, Fn done, Fn fail) { const auto callback = [=](Fn applyUpdates, mtpRequestId id) { applyUpdates(); done(id); }; EditMessage( item, options, callback, fail, MTP_inputMediaTodo(TodoListDataToMTP(&data))); } namespace Fork { void EditMessageMedia( not_null item, Api::SendOptions options, MTPInputMedia media, Fn fail) { EditMessage(item, options, []{}, fail, media); // EditMessageWithUploadedMedia(item, options, media, fail); } } // namespace Fork } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_editing.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once class HistoryItem; namespace Data { struct WebPageDraft; } // namespace Data namespace MTP { class Error; } // namespace MTP namespace Api { struct SendOptions; struct RemoteFileInfo; const auto kDefaultEditMessagesErrors = { u"MESSAGE_ID_INVALID"_q, u"CHAT_ADMIN_REQUIRED"_q, u"MESSAGE_EDIT_TIME_EXPIRED"_q, }; void RescheduleMessage( not_null item, SendOptions options); void EditMessageWithUploadedDocument( HistoryItem *item, RemoteFileInfo info, SendOptions options); void EditMessageWithUploadedPhoto( HistoryItem *item, RemoteFileInfo info, SendOptions options); mtpRequestId EditCaption( not_null item, const TextWithEntities &caption, SendOptions options, Fn done, Fn fail); mtpRequestId EditTextMessage( not_null item, const TextWithEntities &caption, Data::WebPageDraft webpage, SendOptions options, Fn done, Fn fail, bool spoilered); void EditTodoList( not_null item, const TodoListData &data, SendOptions options, Fn done, Fn fail); namespace Fork { void EditMessageMedia( not_null item, Api::SendOptions options, MTPInputMedia media, Fn fail); } // namespace Fork } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_filter_updates.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once namespace Api { template void PerformForUpdate( const MTPUpdates &updates, Fn callback) { updates.match([&](const MTPDupdates &updates) { for (const auto &update : updates.vupdates().v) { update.match([&](const Type &d) { callback(d); }, [](const auto &) { }); } }, [](const auto &) { }); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_global_privacy.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_global_privacy.h" #include "apiwrap.h" #include "data/components/promo_suggestions.h" #include "data/data_user.h" #include "main/main_session.h" #include "main/main_app_config.h" namespace Api { PeerId ParsePaidReactionShownPeer( not_null session, const MTPPaidReactionPrivacy &value) { return value.match([&](const MTPDpaidReactionPrivacyDefault &) { return session->userPeerId(); }, [](const MTPDpaidReactionPrivacyAnonymous &) { return PeerId(); }, [&](const MTPDpaidReactionPrivacyPeer &data) { return data.vpeer().match([&](const MTPDinputPeerSelf &) { return session->userPeerId(); }, [](const MTPDinputPeerUser &data) { return peerFromUser(data.vuser_id()); }, [](const MTPDinputPeerChat &data) { return peerFromChat(data.vchat_id()); }, [](const MTPDinputPeerChannel &data) { return peerFromChannel(data.vchannel_id()); }, [](const MTPDinputPeerUserFromMessage &data) -> PeerId { Unexpected("From message peer in ParsePaidReactionShownPeer."); }, [](const MTPDinputPeerChannelFromMessage &data) -> PeerId { Unexpected("From message peer in ParsePaidReactionShownPeer."); }, [](const MTPDinputPeerEmpty &) -> PeerId { Unexpected("Empty peer in ParsePaidReactionShownPeer."); }); }); } GlobalPrivacy::GlobalPrivacy(not_null api) : _session(&api->session()) , _api(&api->instance()) { } void GlobalPrivacy::reload(Fn callback) { if (callback) { _callbacks.push_back(std::move(callback)); } if (_requestId) { return; } _requestId = _api.request(MTPaccount_GetGlobalPrivacySettings( )).done([=](const MTPGlobalPrivacySettings &result) { _requestId = 0; apply(result); for (const auto &callback : base::take(_callbacks)) { callback(); } }).fail([=] { _requestId = 0; for (const auto &callback : base::take(_callbacks)) { callback(); } }).send(); _session->appConfig().value( ) | rpl::on_next([=] { _showArchiveAndMute = _session->appConfig().get( u"autoarchive_setting_available"_q, false); }, _session->lifetime()); } bool GlobalPrivacy::archiveAndMuteCurrent() const { return _archiveAndMute.current(); } rpl::producer GlobalPrivacy::archiveAndMute() const { return _archiveAndMute.value(); } UnarchiveOnNewMessage GlobalPrivacy::unarchiveOnNewMessageCurrent() const { return _unarchiveOnNewMessage.current(); } auto GlobalPrivacy::unarchiveOnNewMessage() const -> rpl::producer { return _unarchiveOnNewMessage.value(); } rpl::producer GlobalPrivacy::showArchiveAndMute() const { using namespace rpl::mappers; return rpl::combine( archiveAndMute(), _showArchiveAndMute.value(), _1 || _2); } rpl::producer<> GlobalPrivacy::suggestArchiveAndMute() const { return _session->promoSuggestions().requested(u"AUTOARCHIVE_POPULAR"_q); } void GlobalPrivacy::dismissArchiveAndMuteSuggestion() { _session->promoSuggestions().dismiss(u"AUTOARCHIVE_POPULAR"_q); } void GlobalPrivacy::updateHideReadTime(bool hide) { update( archiveAndMuteCurrent(), unarchiveOnNewMessageCurrent(), hide, newRequirePremiumCurrent(), newChargeStarsCurrent(), disallowedGiftTypesCurrent()); } bool GlobalPrivacy::hideReadTimeCurrent() const { return _hideReadTime.current(); } rpl::producer GlobalPrivacy::hideReadTime() const { return _hideReadTime.value(); } bool GlobalPrivacy::newRequirePremiumCurrent() const { return _newRequirePremium.current(); } rpl::producer GlobalPrivacy::newRequirePremium() const { return _newRequirePremium.value(); } int GlobalPrivacy::newChargeStarsCurrent() const { return _newChargeStars.current(); } rpl::producer GlobalPrivacy::newChargeStars() const { return _newChargeStars.value(); } void GlobalPrivacy::updateMessagesPrivacy( bool requirePremium, int chargeStars) { update( archiveAndMuteCurrent(), unarchiveOnNewMessageCurrent(), hideReadTimeCurrent(), requirePremium, chargeStars, disallowedGiftTypesCurrent()); } DisallowedGiftTypes GlobalPrivacy::disallowedGiftTypesCurrent() const { return _disallowedGiftTypes.current(); } auto GlobalPrivacy::disallowedGiftTypes() const -> rpl::producer { return _disallowedGiftTypes.value(); } void GlobalPrivacy::updateDisallowedGiftTypes(DisallowedGiftTypes types) { update( archiveAndMuteCurrent(), unarchiveOnNewMessageCurrent(), hideReadTimeCurrent(), newRequirePremiumCurrent(), newChargeStarsCurrent(), types); } void GlobalPrivacy::loadPaidReactionShownPeer() { if (_paidReactionShownPeerLoaded) { return; } _paidReactionShownPeerLoaded = true; _api.request(MTPmessages_GetPaidReactionPrivacy( )).done([=](const MTPUpdates &result) { _session->api().applyUpdates(result); }).send(); } void GlobalPrivacy::updatePaidReactionShownPeer(PeerId shownPeer) { _paidReactionShownPeer = shownPeer; } PeerId GlobalPrivacy::paidReactionShownPeerCurrent() const { return _paidReactionShownPeer.current(); } rpl::producer GlobalPrivacy::paidReactionShownPeer() const { return _paidReactionShownPeer.value(); } void GlobalPrivacy::updateArchiveAndMute(bool value) { update( value, unarchiveOnNewMessageCurrent(), hideReadTimeCurrent(), newRequirePremiumCurrent(), newChargeStarsCurrent(), disallowedGiftTypesCurrent()); } void GlobalPrivacy::updateUnarchiveOnNewMessage( UnarchiveOnNewMessage value) { update( archiveAndMuteCurrent(), value, hideReadTimeCurrent(), newRequirePremiumCurrent(), newChargeStarsCurrent(), disallowedGiftTypesCurrent()); } void GlobalPrivacy::update( bool archiveAndMute, UnarchiveOnNewMessage unarchiveOnNewMessage, bool hideReadTime, bool newRequirePremium, int newChargeStars, DisallowedGiftTypes disallowedGiftTypes) { using Flag = MTPDglobalPrivacySettings::Flag; using DisallowedFlag = MTPDdisallowedGiftsSettings::Flag; _api.request(_requestId).cancel(); const auto newRequirePremiumAllowed = _session->premium() || _session->appConfig().newRequirePremiumFree(); const auto showGiftIcon = (disallowedGiftTypes & DisallowedGiftType::SendHide); const auto flags = Flag() | (archiveAndMute ? Flag::f_archive_and_mute_new_noncontact_peers : Flag()) | (unarchiveOnNewMessage == UnarchiveOnNewMessage::None ? Flag::f_keep_archived_unmuted : Flag()) | (unarchiveOnNewMessage != UnarchiveOnNewMessage::AnyUnmuted ? Flag::f_keep_archived_folders : Flag()) | (hideReadTime ? Flag::f_hide_read_marks : Flag()) | ((newRequirePremium && newRequirePremiumAllowed) ? Flag::f_new_noncontact_peers_require_premium : Flag()) | Flag::f_noncontact_peers_paid_stars | (showGiftIcon ? Flag::f_display_gifts_button : Flag()) | Flag::f_disallowed_gifts; const auto disallowedFlags = DisallowedFlag() | ((disallowedGiftTypes & DisallowedGiftType::Premium) ? DisallowedFlag::f_disallow_premium_gifts : DisallowedFlag()) | ((disallowedGiftTypes & DisallowedGiftType::Unlimited) ? DisallowedFlag::f_disallow_unlimited_stargifts : DisallowedFlag()) | ((disallowedGiftTypes & DisallowedGiftType::Limited) ? DisallowedFlag::f_disallow_limited_stargifts : DisallowedFlag()) | ((disallowedGiftTypes & DisallowedGiftType::Unique) ? DisallowedFlag::f_disallow_unique_stargifts : DisallowedFlag()) | ((disallowedGiftTypes & DisallowedGiftType::FromChannels) ? DisallowedFlag::f_disallow_stargifts_from_channels : DisallowedFlag()); const auto typesWas = _disallowedGiftTypes.current(); const auto typesChanged = (typesWas != disallowedGiftTypes); _requestId = _api.request(MTPaccount_SetGlobalPrivacySettings( MTP_globalPrivacySettings( MTP_flags(flags), MTP_long(newChargeStars), MTP_disallowedGiftsSettings(MTP_flags(disallowedFlags))) )).done([=](const MTPGlobalPrivacySettings &result) { _requestId = 0; apply(result); if (typesChanged) { _session->user()->updateFullForced(); } }).fail([=](const MTP::Error &error) { _requestId = 0; if (error.type() == u"PREMIUM_ACCOUNT_REQUIRED"_q) { update( archiveAndMute, unarchiveOnNewMessage, hideReadTime, false, 0, DisallowedGiftTypes()); } }).send(); _archiveAndMute = archiveAndMute; _unarchiveOnNewMessage = unarchiveOnNewMessage; _hideReadTime = hideReadTime; _newRequirePremium = newRequirePremium; _newChargeStars = newChargeStars; _disallowedGiftTypes = disallowedGiftTypes; } void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &settings) { const auto &data = settings.data(); _archiveAndMute = data.is_archive_and_mute_new_noncontact_peers(); _unarchiveOnNewMessage = data.is_keep_archived_unmuted() ? UnarchiveOnNewMessage::None : data.is_keep_archived_folders() ? UnarchiveOnNewMessage::NotInFoldersUnmuted : UnarchiveOnNewMessage::AnyUnmuted; _hideReadTime = data.is_hide_read_marks(); _newRequirePremium = data.is_new_noncontact_peers_require_premium(); _newChargeStars = data.vnoncontact_peers_paid_stars().value_or_empty(); if (const auto gifts = data.vdisallowed_gifts()) { const auto &disallow = gifts->data(); _disallowedGiftTypes = DisallowedGiftType() | (disallow.is_disallow_unlimited_stargifts() ? DisallowedGiftType::Unlimited : DisallowedGiftType()) | (disallow.is_disallow_limited_stargifts() ? DisallowedGiftType::Limited : DisallowedGiftType()) | (disallow.is_disallow_unique_stargifts() ? DisallowedGiftType::Unique : DisallowedGiftType()) | (disallow.is_disallow_premium_gifts() ? DisallowedGiftType::Premium : DisallowedGiftType()) | (disallow.is_disallow_stargifts_from_channels() ? DisallowedGiftType::FromChannels : DisallowedGiftType()) | (data.is_display_gifts_button() ? DisallowedGiftType::SendHide : DisallowedGiftType()); } else { _disallowedGiftTypes = data.is_display_gifts_button() ? DisallowedGiftType::SendHide : DisallowedGiftType(); } } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_global_privacy.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "base/flags.h" #include "mtproto/sender.h" class ApiWrap; namespace Main { class Session; } // namespace Main namespace Api { enum class UnarchiveOnNewMessage { None, NotInFoldersUnmuted, AnyUnmuted, }; enum class DisallowedGiftType : uchar { Limited = 0x01, Unlimited = 0x02, Unique = 0x04, FromChannels = 0x08, Premium = 0x10, SendHide = 0x20, }; inline constexpr bool is_flag_type(DisallowedGiftType) { return true; } using DisallowedGiftTypes = base::flags; [[nodiscard]] PeerId ParsePaidReactionShownPeer( not_null session, const MTPPaidReactionPrivacy &value); class GlobalPrivacy final { public: explicit GlobalPrivacy(not_null api); void reload(Fn callback = nullptr); void updateArchiveAndMute(bool value); void updateUnarchiveOnNewMessage(UnarchiveOnNewMessage value); [[nodiscard]] bool archiveAndMuteCurrent() const; [[nodiscard]] rpl::producer archiveAndMute() const; [[nodiscard]] auto unarchiveOnNewMessageCurrent() const -> UnarchiveOnNewMessage; [[nodiscard]] auto unarchiveOnNewMessage() const -> rpl::producer; [[nodiscard]] rpl::producer showArchiveAndMute() const; [[nodiscard]] rpl::producer<> suggestArchiveAndMute() const; void dismissArchiveAndMuteSuggestion(); void updateHideReadTime(bool hide); [[nodiscard]] bool hideReadTimeCurrent() const; [[nodiscard]] rpl::producer hideReadTime() const; [[nodiscard]] bool newRequirePremiumCurrent() const; [[nodiscard]] rpl::producer newRequirePremium() const; [[nodiscard]] int newChargeStarsCurrent() const; [[nodiscard]] rpl::producer newChargeStars() const; void updateMessagesPrivacy(bool requirePremium, int chargeStars); [[nodiscard]] DisallowedGiftTypes disallowedGiftTypesCurrent() const; [[nodiscard]] auto disallowedGiftTypes() const -> rpl::producer; void updateDisallowedGiftTypes(DisallowedGiftTypes types); void loadPaidReactionShownPeer(); void updatePaidReactionShownPeer(PeerId shownPeer); [[nodiscard]] PeerId paidReactionShownPeerCurrent() const; [[nodiscard]] rpl::producer paidReactionShownPeer() const; private: void apply(const MTPGlobalPrivacySettings &settings); void update( bool archiveAndMute, UnarchiveOnNewMessage unarchiveOnNewMessage, bool hideReadTime, bool newRequirePremium, int newChargeStars, DisallowedGiftTypes disallowedGiftTypes); const not_null _session; MTP::Sender _api; mtpRequestId _requestId = 0; rpl::variable _archiveAndMute = false; rpl::variable _unarchiveOnNewMessage = UnarchiveOnNewMessage::None; rpl::variable _showArchiveAndMute = false; rpl::variable _hideReadTime = false; rpl::variable _newRequirePremium = false; rpl::variable _newChargeStars = 0; rpl::variable _disallowedGiftTypes; rpl::variable _paidReactionShownPeer = false; std::vector> _callbacks; bool _paidReactionShownPeerLoaded = false; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_hash.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_hash.h" #include "data/data_document.h" #include "data/data_session.h" #include "data/stickers/data_stickers.h" #include "main/main_session.h" namespace Api { namespace { [[nodiscard]] uint64 CountDocumentVectorHash( const QVector vector) { auto result = HashInit(); for (const auto document : vector) { HashUpdate(result, document->id); } return HashFinalize(result); } [[nodiscard]] uint64 CountSpecialStickerSetHash( not_null session, uint64 setId) { const auto &sets = session->data().stickers().sets(); const auto it = sets.find(setId); if (it != sets.cend()) { return CountDocumentVectorHash(it->second->stickers); } return 0; } [[nodiscard]] uint64 CountStickersOrderHash( not_null session, const Data::StickersSetsOrder &order, bool checkOutdatedInfo) { using Flag = Data::StickersSetFlag; auto result = HashInit(); bool foundOutdated = false; const auto &sets = session->data().stickers().sets(); for (auto i = order.cbegin(), e = order.cend(); i != e; ++i) { auto it = sets.find(*i); if (it != sets.cend()) { const auto set = it->second.get(); if (set->id == Data::Stickers::DefaultSetId) { foundOutdated = true; } else if (!(set->flags & Flag::Special) && !(set->flags & Flag::Archived)) { HashUpdate(result, set->hash); } } } return (!checkOutdatedInfo || !foundOutdated) ? HashFinalize(result) : 0; } [[nodiscard]] uint64 CountFeaturedHash( not_null session, const Data::StickersSetsOrder &order) { auto result = HashInit(); const auto &sets = session->data().stickers().sets(); for (const auto setId : order) { HashUpdate(result, setId); const auto it = sets.find(setId); if (it != sets.cend() && (it->second->flags & Data::StickersSetFlag::Unread)) { HashUpdate(result, 1); } } return HashFinalize(result); } } // namespace uint64 CountStickersHash( not_null session, bool checkOutdatedInfo) { return CountStickersOrderHash( session, session->data().stickers().setsOrder(), checkOutdatedInfo); } uint64 CountMasksHash( not_null session, bool checkOutdatedInfo) { return CountStickersOrderHash( session, session->data().stickers().maskSetsOrder(), checkOutdatedInfo); } uint64 CountCustomEmojiHash( not_null session, bool checkOutdatedInfo) { return CountStickersOrderHash( session, session->data().stickers().emojiSetsOrder(), checkOutdatedInfo); } uint64 CountRecentStickersHash( not_null session, bool attached) { return CountSpecialStickerSetHash( session, attached ? Data::Stickers::CloudRecentAttachedSetId : Data::Stickers::CloudRecentSetId); } uint64 CountFavedStickersHash(not_null session) { return CountSpecialStickerSetHash(session, Data::Stickers::FavedSetId); } uint64 CountFeaturedStickersHash(not_null session) { return CountFeaturedHash( session, session->data().stickers().featuredSetsOrder()); } uint64 CountFeaturedEmojiHash(not_null session) { return CountFeaturedHash( session, session->data().stickers().featuredEmojiSetsOrder()); } uint64 CountSavedGifsHash(not_null session) { return CountDocumentVectorHash(session->data().stickers().savedGifs()); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_hash.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once namespace Main { class Session; } // namespace Main namespace Api { [[nodiscard]] uint64 CountStickersHash( not_null session, bool checkOutdatedInfo = false); [[nodiscard]] uint64 CountMasksHash( not_null session, bool checkOutdatedInfo = false); [[nodiscard]] uint64 CountCustomEmojiHash( not_null session, bool checkOutdatedInfo = false); [[nodiscard]] uint64 CountRecentStickersHash( not_null session, bool attached = false); [[nodiscard]] uint64 CountFavedStickersHash( not_null session); [[nodiscard]] uint64 CountFeaturedStickersHash( not_null session); [[nodiscard]] uint64 CountFeaturedEmojiHash( not_null session); [[nodiscard]] uint64 CountSavedGifsHash(not_null session); [[nodiscard]] inline uint64 HashInit() { return 0; } inline void HashUpdate(uint64 &already, uint64 value) { already ^= (already >> 21); already ^= (already << 35); already ^= (already >> 4); already += value; } inline void HashUpdate(uint64 &already, int64 value) { HashUpdate(already, uint64(value)); } inline void HashUpdate(uint64 &already, uint32 value) { HashUpdate(already, uint64(value)); } inline void HashUpdate(uint64 &already, int32 value) { HashUpdate(already, int64(value)); } [[nodiscard]] inline uint64 HashFinalize(uint64 already) { return already; } template [[nodiscard]] inline uint64 CountHash(IntRange &&range) { auto result = HashInit(); for (const auto value : range) { HashUpdate(result, value); } return HashFinalize(result); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_invite_links.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_invite_links.h" #include "api/api_chat_participants.h" #include "data/data_changes.h" #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_peer.h" #include "data/data_session.h" #include "data/data_user.h" #include "main/main_session.h" #include "base/unixtime.h" #include "apiwrap.h" namespace Api { namespace { constexpr auto kFirstPage = 10; constexpr auto kPerPage = 50; constexpr auto kJoinedFirstPage = 10; void BringPermanentToFront(PeerInviteLinks &links) { auto &list = links.links; const auto i = ranges::find_if(list, [](const InviteLink &link) { return link.permanent && !link.revoked; }); if (i != end(list) && i != begin(list)) { ranges::rotate(begin(list), i, i + 1); } } void RemovePermanent(PeerInviteLinks &links) { auto &list = links.links; list.erase(ranges::remove_if(list, [](const InviteLink &link) { return link.permanent && !link.revoked; }), end(list)); } } // namespace JoinedByLinkSlice ParseJoinedByLinkSlice( not_null peer, const MTPmessages_ChatInviteImporters &slice) { auto result = JoinedByLinkSlice(); slice.match([&](const MTPDmessages_chatInviteImporters &data) { auto &owner = peer->session().data(); owner.processUsers(data.vusers()); result.count = data.vcount().v; result.users.reserve(data.vimporters().v.size()); for (const auto &importer : data.vimporters().v) { importer.match([&](const MTPDchatInviteImporter &data) { result.users.push_back({ .user = owner.user(data.vuser_id()), .date = data.vdate().v, .viaFilterLink = data.is_via_chatlist(), }); }); } }); return result; } InviteLinks::InviteLinks(not_null api) : _api(api) { } void InviteLinks::create(const CreateInviteLinkArgs &args) { performCreate(args, false); } void InviteLinks::performCreate( const CreateInviteLinkArgs &args, bool revokeLegacyPermanent) { if (const auto i = _createCallbacks.find(args.peer) ; i != end(_createCallbacks)) { if (args.done) { i->second.push_back(std::move(args.done)); } return; } auto &callbacks = _createCallbacks[args.peer]; if (args.done) { callbacks.push_back(std::move(args.done)); } const auto requestApproval = !args.subscription && args.requestApproval; using Flag = MTPmessages_ExportChatInvite::Flag; _api->request(MTPmessages_ExportChatInvite( MTP_flags((revokeLegacyPermanent ? Flag::f_legacy_revoke_permanent : Flag(0)) | (!args.label.isEmpty() ? Flag::f_title : Flag(0)) | (args.expireDate ? Flag::f_expire_date : Flag(0)) | ((!requestApproval && args.usageLimit) ? Flag::f_usage_limit : Flag(0)) | (requestApproval ? Flag::f_request_needed : Flag(0)) | (args.subscription ? Flag::f_subscription_pricing : Flag(0))), args.peer->input(), MTP_int(args.expireDate), MTP_int(args.usageLimit), MTP_string(args.label), MTP_starsSubscriptionPricing( MTP_int(args.subscription.period), MTP_long(args.subscription.credits)) )).done([=, peer = args.peer](const MTPExportedChatInvite &result) { const auto callbacks = _createCallbacks.take(peer); const auto link = prepend(peer, peer->session().user(), result); if (link && callbacks) { for (const auto &callback : *callbacks) { callback(*link); } } }).fail([=, peer = args.peer] { _createCallbacks.erase(peer); }).send(); } auto InviteLinks::lookupMyPermanent(not_null peer) -> Link* { auto i = _firstSlices.find(peer); return (i != end(_firstSlices)) ? lookupMyPermanent(i->second) : nullptr; } auto InviteLinks::lookupMyPermanent(Links &links) -> Link* { const auto first = links.links.begin(); return (first != end(links.links) && first->permanent && !first->revoked) ? &*first : nullptr; } auto InviteLinks::lookupMyPermanent(const Links &links) const -> const Link* { const auto first = links.links.begin(); return (first != end(links.links) && first->permanent && !first->revoked) ? &*first : nullptr; } auto InviteLinks::prepend( not_null peer, not_null admin, const MTPExportedChatInvite &invite) -> std::optional { const auto link = parse(peer, invite); if (!link) { return link; } if (admin->isSelf()) { prependMyToFirstSlice(peer, admin, *link); } _updates.fire(Update{ .peer = peer, .admin = admin, .now = *link }); return link; } void InviteLinks::prependMyToFirstSlice( not_null peer, not_null admin, const Link &link) { Expects(admin->isSelf()); auto i = _firstSlices.find(peer); if (i == end(_firstSlices)) { i = _firstSlices.emplace(peer).first; } auto &links = i->second; const auto permanent = lookupMyPermanent(links); const auto hadPermanent = (permanent != nullptr); auto updateOldPermanent = Update{ .peer = peer, .admin = admin, }; if (link.permanent && hadPermanent) { updateOldPermanent.was = permanent->link; updateOldPermanent.now = *permanent; updateOldPermanent.now->revoked = true; links.links.erase(begin(links.links)); if (links.count > 0) { --links.count; } } // Must not dereference 'permanent' pointer after that. ++links.count; if (hadPermanent && !link.permanent) { links.links.insert(begin(links.links) + 1, link); } else { links.links.insert(begin(links.links), link); } if (link.permanent) { editPermanentLink(peer, link.link); } notify(peer); if (updateOldPermanent.now) { _updates.fire(std::move(updateOldPermanent)); } } void InviteLinks::edit( not_null peer, not_null admin, const QString &link, const QString &label, TimeId expireDate, int usageLimit, bool requestApproval, Fn done) { performEdit( peer, admin, link, std::move(done), false, label, expireDate, usageLimit, requestApproval); } void InviteLinks::editTitle( not_null peer, not_null admin, const QString &link, const QString &label, Fn done) { performEdit(peer, admin, link, done, false, label, 0, 0, false, true); } void InviteLinks::performEdit( not_null peer, not_null admin, const QString &link, Fn done, bool revoke, const QString &label, TimeId expireDate, int usageLimit, bool requestApproval, bool editOnlyTitle) { const auto key = LinkKey{ peer, link }; if (_deleteCallbacks.contains(key)) { return; } else if (const auto i = _editCallbacks.find(key) ; i != end(_editCallbacks)) { if (done) { i->second.push_back(std::move(done)); } return; } auto &callbacks = _editCallbacks[key]; if (done) { callbacks.push_back(std::move(done)); } using Flag = MTPmessages_EditExportedChatInvite::Flag; const auto flags = (revoke ? Flag::f_revoked : Flag(0)) | (!revoke ? Flag::f_title : Flag(0)) | (!revoke ? Flag::f_expire_date : Flag(0)) | ((!revoke && !requestApproval) ? Flag::f_usage_limit : Flag(0)) | ((!revoke && (requestApproval || !usageLimit)) ? Flag::f_request_needed : Flag(0)); _api->request(MTPmessages_EditExportedChatInvite( MTP_flags(editOnlyTitle ? Flag::f_title : flags), peer->input(), MTP_string(link), MTP_int(expireDate), MTP_int(usageLimit), MTP_bool(requestApproval), MTP_string(label) )).done([=](const MTPmessages_ExportedChatInvite &result) { const auto callbacks = _editCallbacks.take(key); const auto peer = key.peer; result.match([&](const auto &data) { _api->session().data().processUsers(data.vusers()); const auto link = parse(peer, data.vinvite()); if (!link) { return; } auto i = _firstSlices.find(peer); if (i != end(_firstSlices)) { const auto j = ranges::find( i->second.links, key.link, &Link::link); if (j != end(i->second.links)) { if (link->revoked && !j->revoked) { i->second.links.erase(j); if (i->second.count > 0) { --i->second.count; } } else { *j = *link; } } } for (const auto &callback : *callbacks) { callback(*link); } _updates.fire(Update{ .peer = peer, .admin = admin, .was = key.link, .now = link, }); using Replaced = MTPDmessages_exportedChatInviteReplaced; if constexpr (Replaced::Is()) { prepend(peer, admin, data.vnew_invite()); } }); }).fail([=] { _editCallbacks.erase(key); }).send(); } void InviteLinks::revoke( not_null peer, not_null admin, const QString &link, Fn done) { performEdit(peer, admin, link, std::move(done), true); } void InviteLinks::revokePermanent( not_null peer, not_null admin, const QString &link, Fn done) { const auto callback = [=](auto&&) { done(); }; if (!link.isEmpty()) { performEdit(peer, admin, link, callback, true); } else if (!admin->isSelf()) { crl::on_main(&peer->session(), done); } else { performCreate({ peer, callback }, true); } } void InviteLinks::destroy( not_null peer, not_null admin, const QString &link, Fn done) { const auto key = LinkKey{ peer, link }; if (const auto i = _deleteCallbacks.find(key) ; i != end(_deleteCallbacks)) { if (done) { i->second.push_back(std::move(done)); } return; } auto &callbacks = _deleteCallbacks[key]; if (done) { callbacks.push_back(std::move(done)); } _api->request(MTPmessages_DeleteExportedChatInvite( peer->input(), MTP_string(link) )).done([=] { const auto callbacks = _deleteCallbacks.take(key); if (callbacks) { for (const auto &callback : *callbacks) { callback(); } } _updates.fire(Update{ .peer = peer, .admin = admin, .was = key.link, }); }).fail([=] { _deleteCallbacks.erase(key); }).send(); } void InviteLinks::destroyAllRevoked( not_null peer, not_null admin, Fn done) { if (const auto i = _deleteRevokedCallbacks.find(peer) ; i != end(_deleteRevokedCallbacks)) { if (done) { i->second.push_back(std::move(done)); } return; } auto &callbacks = _deleteRevokedCallbacks[peer]; if (done) { callbacks.push_back(std::move(done)); } _api->request(MTPmessages_DeleteRevokedExportedChatInvites( peer->input(), admin->inputUser() )).done([=] { if (const auto callbacks = _deleteRevokedCallbacks.take(peer)) { for (const auto &callback : *callbacks) { callback(); } } _allRevokedDestroyed.fire({ peer, admin }); }).send(); } void InviteLinks::requestMyLinks(not_null peer) { if (_firstSliceRequests.contains(peer)) { return; } const auto requestId = _api->request(MTPmessages_GetExportedChatInvites( MTP_flags(0), peer->input(), MTP_inputUserSelf(), MTPint(), // offset_date MTPstring(), // offset_link MTP_int(kFirstPage) )).done([=](const MTPmessages_ExportedChatInvites &result) { _firstSliceRequests.remove(peer); auto slice = parseSlice(peer, result); auto i = _firstSlices.find(peer); const auto permanent = (i != end(_firstSlices)) ? lookupMyPermanent(i->second) : nullptr; if (!permanent) { BringPermanentToFront(slice); const auto j = _firstSlices.emplace_or_assign( peer, std::move(slice)).first; if (const auto permanent = lookupMyPermanent(j->second)) { editPermanentLink(peer, permanent->link); } } else { RemovePermanent(slice); auto &existing = i->second.links; existing.erase(begin(existing) + 1, end(existing)); existing.insert( end(existing), begin(slice.links), end(slice.links)); i->second.count = std::max(slice.count, int(existing.size())); } notify(peer); }).fail([=] { _firstSliceRequests.remove(peer); }).send(); _firstSliceRequests.emplace(peer, requestId); } void InviteLinks::processRequest( not_null peer, const QString &link, not_null user, bool approved, Fn done, Fn fail) { if (_processRequests.contains({ peer, user })) { return; } _processRequests.emplace( std::pair{ peer, user }, ProcessRequest{ std::move(done), std::move(fail) }); using Flag = MTPmessages_HideChatJoinRequest::Flag; _api->request(MTPmessages_HideChatJoinRequest( MTP_flags(approved ? Flag::f_approved : Flag(0)), peer->input(), user->inputUser() )).done([=](const MTPUpdates &result) { if (const auto chat = peer->asChat()) { if (chat->count > 0) { if (chat->participants.size() >= chat->count) { chat->participants.emplace(user); } ++chat->count; } } else if (const auto channel = peer->asChannel()) { _api->chatParticipants().requestCountDelayed(channel); } _api->applyUpdates(result); if (link.isEmpty() && approved) { // We don't know the link that was used for this user. // Prune all the cache. for (auto i = begin(_firstJoined); i != end(_firstJoined);) { if (i->first.peer == peer) { i = _firstJoined.erase(i); } else { ++i; } } _firstSlices.remove(peer); } else if (approved) { const auto i = _firstJoined.find({ peer, link }); if (i != end(_firstJoined)) { ++i->second.count; i->second.users.insert( begin(i->second.users), JoinedByLinkUser{ user, base::unixtime::now() }); } } if (const auto callbacks = _processRequests.take({ peer, user })) { if (const auto &done = callbacks->done) { done(); } } }).fail([=] { if (const auto callbacks = _processRequests.take({ peer, user })) { if (const auto &fail = callbacks->fail) { fail(); } } }).send(); } void InviteLinks::applyExternalUpdate( not_null peer, InviteLink updated) { if (const auto i = _firstSlices.find(peer); i != end(_firstSlices)) { for (auto &link : i->second.links) { if (link.link == updated.link) { link = updated; } } } _updates.fire({ .peer = peer, .admin = updated.admin, .was = updated.link, .now = updated, }); } std::optional InviteLinks::lookupJoinedFirstSlice( LinkKey key) const { const auto i = _firstJoined.find(key); return (i != end(_firstJoined)) ? std::make_optional(i->second) : std::nullopt; } std::optional InviteLinks::joinedFirstSliceLoaded( not_null peer, const QString &link) const { return lookupJoinedFirstSlice({ peer, link }); } rpl::producer InviteLinks::joinedFirstSliceValue( not_null peer, const QString &link, int fullCount) { const auto key = LinkKey{ peer, link }; auto current = lookupJoinedFirstSlice(key).value_or(JoinedByLinkSlice()); if (current.count == fullCount && (!fullCount || !current.users.empty())) { return rpl::single(current); } current.count = fullCount; const auto remove = int(current.users.size()) - current.count; if (remove > 0) { current.users.erase(end(current.users) - remove, end(current.users)); } requestJoinedFirstSlice(key); using namespace rpl::mappers; return rpl::single( current ) | rpl::then(_joinedFirstSliceLoaded.events( ) | rpl::filter( _1 == key ) | rpl::map([=] { return lookupJoinedFirstSlice(key).value_or(JoinedByLinkSlice()); })); } auto InviteLinks::updates( not_null peer, not_null admin) const -> rpl::producer { return _updates.events() | rpl::filter([=](const Update &update) { return update.peer == peer && update.admin == admin; }); } rpl::producer<> InviteLinks::allRevokedDestroyed( not_null peer, not_null admin) const { return _allRevokedDestroyed.events( ) | rpl::filter([=](const AllRevokedDestroyed &which) { return which.peer == peer && which.admin == admin; }) | rpl::to_empty; } void InviteLinks::requestJoinedFirstSlice(LinkKey key) { if (_firstJoinedRequests.contains(key)) { return; } const auto requestId = _api->request(MTPmessages_GetChatInviteImporters( MTP_flags(MTPmessages_GetChatInviteImporters::Flag::f_link), key.peer->input(), MTP_string(key.link), MTPstring(), // q MTP_int(0), // offset_date MTP_inputUserEmpty(), // offset_user MTP_int(kJoinedFirstPage) )).done([=](const MTPmessages_ChatInviteImporters &result) { _firstJoinedRequests.remove(key); _firstJoined[key] = ParseJoinedByLinkSlice(key.peer, result); _joinedFirstSliceLoaded.fire_copy(key); }).fail([=] { _firstJoinedRequests.remove(key); }).send(); _firstJoinedRequests.emplace(key, requestId); } void InviteLinks::setMyPermanent( not_null peer, const MTPExportedChatInvite &invite) { auto link = parse(peer, invite); if (!link) { LOG(("API Error: " "InviteLinks::setPermanent called with non-link.")); return; } else if (!link->permanent) { LOG(("API Error: " "InviteLinks::setPermanent called with non-permanent link.")); return; } auto i = _firstSlices.find(peer); if (i == end(_firstSlices)) { i = _firstSlices.emplace(peer).first; } auto &links = i->second; auto updateOldPermanent = Update{ .peer = peer, .admin = peer->session().user(), }; if (const auto permanent = lookupMyPermanent(links)) { if (permanent->link == link->link) { if (permanent->usage != link->usage) { permanent->usage = link->usage; _updates.fire(Update{ .peer = peer, .admin = peer->session().user(), .was = link->link, .now = *permanent }); } return; } updateOldPermanent.was = permanent->link; updateOldPermanent.now = *permanent; updateOldPermanent.now->revoked = true; links.links.erase(begin(links.links)); if (links.count > 0) { --links.count; } } links.links.insert(begin(links.links), *link); editPermanentLink(peer, link->link); notify(peer); if (updateOldPermanent.now) { _updates.fire(std::move(updateOldPermanent)); } _updates.fire(Update{ .peer = peer, .admin = peer->session().user(), .now = link }); } void InviteLinks::clearMyPermanent(not_null peer) { auto i = _firstSlices.find(peer); if (i == end(_firstSlices)) { return; } auto &links = i->second; const auto permanent = lookupMyPermanent(links); if (!permanent) { return; } auto updateOldPermanent = Update{ .peer = peer, .admin = peer->session().user() }; updateOldPermanent.was = permanent->link; updateOldPermanent.now = *permanent; updateOldPermanent.now->revoked = true; links.links.erase(begin(links.links)); if (links.count > 0) { --links.count; } editPermanentLink(peer, QString()); notify(peer); if (updateOldPermanent.now) { _updates.fire(std::move(updateOldPermanent)); } } void InviteLinks::notify(not_null peer) { peer->session().changes().peerUpdated( peer, Data::PeerUpdate::Flag::InviteLinks); } auto InviteLinks::myLinks(not_null peer) const -> const Links & { static const auto kEmpty = Links(); const auto i = _firstSlices.find(peer); return (i != end(_firstSlices)) ? i->second : kEmpty; } auto InviteLinks::parseSlice( not_null peer, const MTPmessages_ExportedChatInvites &slice) const -> Links { auto i = _firstSlices.find(peer); const auto permanent = (i != end(_firstSlices)) ? lookupMyPermanent(i->second) : nullptr; auto result = Links(); slice.match([&](const MTPDmessages_exportedChatInvites &data) { peer->session().data().processUsers(data.vusers()); result.count = data.vcount().v; for (const auto &invite : data.vinvites().v) { if (const auto link = parse(peer, invite)) { if (!permanent || link->link != permanent->link) { result.links.push_back(*link); } } } }); return result; } auto InviteLinks::parse( not_null peer, const MTPExportedChatInvite &invite) const -> std::optional { return invite.match([&](const MTPDchatInviteExported &data) { return std::optional(Link{ .link = qs(data.vlink()), .label = qs(data.vtitle().value_or_empty()), .subscription = data.vsubscription_pricing() ? Data::PeerSubscription{ data.vsubscription_pricing()->data().vamount().v, data.vsubscription_pricing()->data().vperiod().v, } : Data::PeerSubscription(), .admin = peer->session().data().user(data.vadmin_id()), .date = data.vdate().v, .startDate = data.vstart_date().value_or_empty(), .expireDate = data.vexpire_date().value_or_empty(), .usageLimit = data.vusage_limit().value_or_empty(), .usage = data.vusage().value_or_empty(), .requested = data.vrequested().value_or_empty(), .requestApproval = data.is_request_needed(), .permanent = data.is_permanent(), .revoked = data.is_revoked(), }); }, [&](const MTPDchatInvitePublicJoinRequests &data) { return std::optional(); }); } void InviteLinks::requestMoreLinks( not_null peer, not_null admin, TimeId lastDate, const QString &lastLink, bool revoked, Fn done) { using Flag = MTPmessages_GetExportedChatInvites::Flag; _api->request(MTPmessages_GetExportedChatInvites( MTP_flags(Flag::f_offset_link | (revoked ? Flag::f_revoked : Flag(0))), peer->input(), admin->inputUser(), MTP_int(lastDate), MTP_string(lastLink), MTP_int(kPerPage) )).done([=](const MTPmessages_ExportedChatInvites &result) { done(parseSlice(peer, result)); }).fail([=] { done(Links()); }).send(); } void InviteLinks::editPermanentLink( not_null peer, const QString &link) { if (const auto chat = peer->asChat()) { chat->setInviteLink(link); } else if (const auto channel = peer->asChannel()) { channel->setInviteLink(link); } else { Unexpected("Peer in InviteLinks::editMainLink."); } } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_invite_links.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once class ApiWrap; #include "data/data_subscriptions.h" namespace Api { struct InviteLink { QString link; QString label; Data::PeerSubscription subscription; not_null admin; TimeId date = 0; TimeId startDate = 0; TimeId expireDate = 0; int usageLimit = 0; int usage = 0; int requested = 0; bool requestApproval = false; bool permanent = false; bool revoked = false; }; struct PeerInviteLinks { std::vector links; int count = 0; }; struct JoinedByLinkUser { not_null user; TimeId date = 0; bool viaFilterLink = false; }; struct JoinedByLinkSlice { std::vector users; int count = 0; }; struct InviteLinkUpdate { not_null peer; not_null admin; QString was; std::optional now; }; [[nodiscard]] JoinedByLinkSlice ParseJoinedByLinkSlice( not_null peer, const MTPmessages_ChatInviteImporters &slice); struct CreateInviteLinkArgs { not_null peer; Fn done = nullptr; QString label; TimeId expireDate = 0; int usageLimit = 0; bool requestApproval = false; Data::PeerSubscription subscription; }; class InviteLinks final { public: explicit InviteLinks(not_null api); using Link = InviteLink; using Links = PeerInviteLinks; using Update = InviteLinkUpdate; void create(const CreateInviteLinkArgs &args); void edit( not_null peer, not_null admin, const QString &link, const QString &label, TimeId expireDate, int usageLimit, bool requestApproval, Fn done = nullptr); void editTitle( not_null peer, not_null admin, const QString &link, const QString &label, Fn done = nullptr); void revoke( not_null peer, not_null admin, const QString &link, Fn done = nullptr); void revokePermanent( not_null peer, not_null admin, const QString &link, Fn done = nullptr); void destroy( not_null peer, not_null admin, const QString &link, Fn done = nullptr); void destroyAllRevoked( not_null peer, not_null admin, Fn done = nullptr); void setMyPermanent( not_null peer, const MTPExportedChatInvite &invite); void clearMyPermanent(not_null peer); void requestMyLinks(not_null peer); [[nodiscard]] const Links &myLinks(not_null peer) const; void processRequest( not_null peer, const QString &link, not_null user, bool approved, Fn done, Fn fail); void applyExternalUpdate(not_null peer, InviteLink updated); [[nodiscard]] rpl::producer joinedFirstSliceValue( not_null peer, const QString &link, int fullCount); [[nodiscard]] std::optional joinedFirstSliceLoaded( not_null peer, const QString &link) const; [[nodiscard]] rpl::producer updates( not_null peer, not_null admin) const; [[nodiscard]] rpl::producer<> allRevokedDestroyed( not_null peer, not_null admin) const; void requestMoreLinks( not_null peer, not_null admin, TimeId lastDate, const QString &lastLink, bool revoked, Fn done); private: struct LinkKey { not_null peer; QString link; friend inline bool operator<(const LinkKey &a, const LinkKey &b) { return (a.peer == b.peer) ? (a.link < b.link) : (a.peer < b.peer); } friend inline bool operator==(const LinkKey &a, const LinkKey &b) { return (a.peer == b.peer) && (a.link == b.link); } }; struct ProcessRequest { Fn done; Fn fail; }; [[nodiscard]] Links parseSlice( not_null peer, const MTPmessages_ExportedChatInvites &slice) const; [[nodiscard]] std::optional parse( not_null peer, const MTPExportedChatInvite &invite) const; [[nodiscard]] Link *lookupMyPermanent(not_null peer); [[nodiscard]] Link *lookupMyPermanent(Links &links); [[nodiscard]] const Link *lookupMyPermanent(const Links &links) const; std::optional prepend( not_null peer, not_null admin, const MTPExportedChatInvite &invite); void prependMyToFirstSlice( not_null peer, not_null admin, const Link &link); void notify(not_null peer); void editPermanentLink( not_null peer, const QString &link); void performEdit( not_null peer, not_null admin, const QString &link, Fn done, bool revoke, const QString &label = QString(), TimeId expireDate = 0, int usageLimit = 0, bool requestApproval = false, bool editOnlyTitle = false); void performCreate( const CreateInviteLinkArgs &args, bool revokeLegacyPermanent); void requestJoinedFirstSlice(LinkKey key); [[nodiscard]] std::optional lookupJoinedFirstSlice( LinkKey key) const; const not_null _api; base::flat_map, Links> _firstSlices; base::flat_map, mtpRequestId> _firstSliceRequests; base::flat_map _firstJoined; base::flat_map _firstJoinedRequests; rpl::event_stream _joinedFirstSliceLoaded; base::flat_map< not_null, std::vector>> _createCallbacks; base::flat_map>> _editCallbacks; base::flat_map>> _deleteCallbacks; base::flat_map< not_null, std::vector>> _deleteRevokedCallbacks; base::flat_map< std::pair, not_null>, ProcessRequest> _processRequests; rpl::event_stream _updates; struct AllRevokedDestroyed { not_null peer; not_null admin; }; rpl::event_stream _allRevokedDestroyed; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_media.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_media.h" #include "api/api_common.h" #include "data/data_document.h" #include "data/stickers/data_stickers_set.h" #include "history/history_item.h" namespace Api { namespace { MTPVector ComposeSendingDocumentAttributes( not_null document) { const auto filenameAttribute = MTP_documentAttributeFilename( MTP_string(document->filename())); const auto dimensions = document->dimensions; auto attributes = QVector(1, filenameAttribute); if (dimensions.width() > 0 && dimensions.height() > 0) { if (document->hasDuration() && !document->hasMimeType(u"image/gif"_q)) { auto flags = MTPDdocumentAttributeVideo::Flags(0); using VideoFlag = MTPDdocumentAttributeVideo::Flag; if (document->isVideoMessage()) { flags |= VideoFlag::f_round_message; } if (document->supportsStreaming()) { flags |= VideoFlag::f_supports_streaming; } attributes.push_back(MTP_documentAttributeVideo( MTP_flags(flags), MTP_double(document->duration() / 1000.), MTP_int(dimensions.width()), MTP_int(dimensions.height()), MTPint(), // preload_prefix_size MTPdouble(), // video_start_ts MTPstring())); // video_codec } else { attributes.push_back(MTP_documentAttributeImageSize( MTP_int(dimensions.width()), MTP_int(dimensions.height()))); } } if (document->type == AnimatedDocument) { attributes.push_back(MTP_documentAttributeAnimated()); } else if (document->type == StickerDocument && document->sticker()) { attributes.push_back(MTP_documentAttributeSticker( MTP_flags(0), MTP_string(document->sticker()->alt), Data::InputStickerSet(document->sticker()->set), MTPMaskCoords())); } else if (const auto song = document->song()) { const auto flags = MTPDdocumentAttributeAudio::Flag::f_title | MTPDdocumentAttributeAudio::Flag::f_performer; attributes.push_back(MTP_documentAttributeAudio( MTP_flags(flags), MTP_int(document->duration() / 1000), MTP_string(song->title), MTP_string(song->performer), MTPstring())); } else if (const auto voice = document->voice()) { const auto flags = MTPDdocumentAttributeAudio::Flag::f_voice | MTPDdocumentAttributeAudio::Flag::f_waveform; attributes.push_back(MTP_documentAttributeAudio( MTP_flags(flags), MTP_int(document->duration() / 1000), MTPstring(), MTPstring(), MTP_bytes(documentWaveformEncode5bit(voice->waveform)))); } return MTP_vector(attributes); } } // namespace MTPInputMedia PrepareUploadedPhoto( not_null item, RemoteFileInfo info) { using Flag = MTPDinputMediaUploadedPhoto::Flag; const auto spoiler = item->media() && item->media()->hasSpoiler(); const auto ttlSeconds = item->media() ? item->media()->ttlSeconds() : 0; const auto flags = (spoiler ? Flag::f_spoiler : Flag()) | (info.attachedStickers.empty() ? Flag() : Flag::f_stickers) | (ttlSeconds ? Flag::f_ttl_seconds : Flag()); return MTP_inputMediaUploadedPhoto( MTP_flags(flags), info.file, MTP_vector( ranges::to>(info.attachedStickers)), MTP_int(ttlSeconds), MTPInputDocument()); // video } MTPInputMedia PrepareUploadedDocument( not_null item, RemoteFileInfo info) { if (!item || !item->media() || !item->media()->document()) { return MTP_inputMediaEmpty(); } using Flag = MTPDinputMediaUploadedDocument::Flag; const auto spoiler = item->media() && item->media()->hasSpoiler(); const auto ttlSeconds = item->media() ? item->media()->ttlSeconds() : 0; const auto flags = (spoiler ? Flag::f_spoiler : Flag()) | (info.thumb ? Flag::f_thumb : Flag()) | (item->groupId() ? Flag::f_nosound_video : Flag()) | (info.forceFile ? Flag::f_force_file : Flag()) | (info.attachedStickers.empty() ? Flag::f_stickers : Flag()) | (ttlSeconds ? Flag::f_ttl_seconds : Flag()) | (info.videoCover ? Flag::f_video_cover : Flag()); const auto document = item->media()->document(); return MTP_inputMediaUploadedDocument( MTP_flags(flags), info.file, info.thumb.value_or(MTPInputFile()), MTP_string(document->mimeString()), ComposeSendingDocumentAttributes(document), MTP_vector( ranges::to>(info.attachedStickers)), info.videoCover.value_or(MTPInputPhoto()), MTP_int(0), // video_timestamp MTP_int(ttlSeconds)); } bool HasAttachedStickers(MTPInputMedia media) { return media.match([&](const MTPDinputMediaUploadedPhoto &photo) -> bool { return (photo.vflags().v & MTPDinputMediaUploadedPhoto::Flag::f_stickers); }, [&](const MTPDinputMediaUploadedDocument &document) -> bool { return (document.vflags().v & MTPDinputMediaUploadedDocument::Flag::f_stickers); }, [](const auto &d) { return false; }); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_media.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once class HistoryItem; namespace Api { struct RemoteFileInfo; MTPInputMedia PrepareUploadedPhoto( not_null item, RemoteFileInfo info); MTPInputMedia PrepareUploadedDocument( not_null item, RemoteFileInfo info); bool HasAttachedStickers(MTPInputMedia media); } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_messages_search.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_messages_search.h" #include "apiwrap.h" #include "data/data_channel.h" #include "data/data_histories.h" #include "data/data_message_reaction_id.h" #include "data/data_peer.h" #include "data/data_session.h" #include "history/history.h" #include "history/history_item.h" #include "main/main_session.h" namespace Api { namespace { constexpr auto kSearchPerPage = 50; [[nodiscard]] MessageIdsList HistoryItemsFromTL( not_null data, const QVector &messages) { auto result = MessageIdsList(); for (const auto &message : messages) { const auto peerId = PeerFromMessage(message); if (data->peerLoaded(peerId)) { if (DateFromMessage(message)) { const auto item = data->addNewMessage( message, MessageFlags(), NewMessageType::Existing); result.push_back(item->fullId()); } } else { LOG(("API Error: a search results with not loaded peer %1" ).arg(peerId.value)); } } return result; } [[nodiscard]] QString RequestToToken( const MessagesSearch::Request &request) { auto result = request.query; if (request.from) { result += '\n' + QString::number(request.from->id.value); } for (const auto &tag : request.tags) { result += '\n'; if (const auto customId = tag.custom()) { result += u"custom"_q + QString::number(customId); } else { result += u"emoji"_q + tag.emoji(); } } switch (request.filter) { case SearchFilter::NoFilter: break; case SearchFilter::Pinned: result += u"\npinned"_q; break; } return result; } [[nodiscard]] MTPMessagesFilter PrepareFilter(SearchFilter filter) { switch (filter) { case SearchFilter::Pinned: return MTP_inputMessagesFilterPinned(); case SearchFilter::NoFilter: return MTP_inputMessagesFilterEmpty(); } return MTP_inputMessagesFilterEmpty(); } } // namespace MessagesSearch::MessagesSearch(not_null history) : _history(history) { } MessagesSearch::~MessagesSearch() { _history->owner().histories().cancelRequest( base::take(_searchInHistoryRequest)); } void MessagesSearch::searchMessages(Request request) { _request = std::move(request); _offsetId = {}; searchRequest(); } void MessagesSearch::searchMore() { if (_searchInHistoryRequest || _requestId) { return; } searchRequest(); } void MessagesSearch::searchRequest() { const auto nextToken = RequestToToken(_request); if (!_offsetId) { const auto it = _cacheOfStartByToken.find(nextToken); if (it != end(_cacheOfStartByToken)) { _requestId = 0; searchReceived(it->second, _requestId, nextToken); return; } } auto callback = [=](Fn finish) { using Flag = MTPmessages_Search::Flag; const auto from = _request.from; const auto fromPeer = _history->peer->isUser() ? nullptr : from; const auto savedPeer = _history->peer->isSelf() ? from : nullptr; _requestId = _history->session().api().request(MTPmessages_Search( MTP_flags((fromPeer ? Flag::f_from_id : Flag()) | (savedPeer ? Flag::f_saved_peer_id : Flag()) | (_request.topMsgId ? Flag::f_top_msg_id : Flag()) | (_request.tags.empty() ? Flag() : Flag::f_saved_reaction)), _history->peer->input(), MTP_string(_request.query), (fromPeer ? fromPeer->input() : MTP_inputPeerEmpty()), (savedPeer ? savedPeer->input() : MTP_inputPeerEmpty()), MTP_vector_from_range(_request.tags | ranges::views::transform( Data::ReactionToMTP )), MTP_int(_request.topMsgId), // top_msg_id PrepareFilter(_request.filter), MTP_int(0), // min_date MTP_int(0), // max_date MTP_int(_offsetId), // offset_id MTP_int(0), // add_offset MTP_int(kSearchPerPage), MTP_int(0), // max_id MTP_int(0), // min_id MTP_long(0) // hash )).done([=](const TLMessages &result, mtpRequestId id) { _searchInHistoryRequest = 0; searchReceived(result, id, nextToken); finish(); }).fail([=](const MTP::Error &error, mtpRequestId id) { _searchInHistoryRequest = 0; if (_requestId == id) { _requestId = 0; } if (error.type() == u"SEARCH_QUERY_EMPTY"_q) { _messagesFounds.fire({ 0, MessageIdsList(), nextToken }); } finish(); }).send(); return _requestId; }; _searchInHistoryRequest = _history->owner().histories().sendRequest( _history, Data::Histories::RequestType::History, std::move(callback)); } void MessagesSearch::searchReceived( const TLMessages &result, mtpRequestId requestId, const QString &nextToken) { if (requestId != _requestId) { return; } auto &owner = _history->owner(); auto found = result.match([&](const MTPDmessages_messages &data) { if (_requestId != 0) { // Don't apply cached data! owner.processUsers(data.vusers()); owner.processChats(data.vchats()); _history->peer->processTopics(data.vtopics()); } auto items = HistoryItemsFromTL(&owner, data.vmessages().v); const auto total = int(data.vmessages().v.size()); return FoundMessages{ total, std::move(items), nextToken }; }, [&](const MTPDmessages_messagesSlice &data) { if (_requestId != 0) { // Don't apply cached data! owner.processUsers(data.vusers()); owner.processChats(data.vchats()); _history->peer->processTopics(data.vtopics()); } auto items = HistoryItemsFromTL(&owner, data.vmessages().v); // data.vnext_rate() is used only in global search. const auto total = int(data.vcount().v); return FoundMessages{ total, std::move(items), nextToken }; }, [&](const MTPDmessages_channelMessages &data) { if (_requestId != 0) { // Don't apply cached data! owner.processUsers(data.vusers()); owner.processChats(data.vchats()); if (const auto channel = _history->peer->asChannel()) { channel->ptsReceived(data.vpts().v); } else { LOG(("API Error: " "received messages.channelMessages when no channel " "was passed!")); } _history->peer->processTopics(data.vtopics()); } auto items = HistoryItemsFromTL(&owner, data.vmessages().v); const auto total = int(data.vcount().v); return FoundMessages{ total, std::move(items), nextToken }; }, [](const MTPDmessages_messagesNotModified &data) { return FoundMessages{}; }); if (!_offsetId) { _cacheOfStartByToken.emplace(nextToken, result); } _requestId = 0; _offsetId = found.messages.empty() ? MsgId() : found.messages.back().msg; _messagesFounds.fire(std::move(found)); } rpl::producer MessagesSearch::messagesFounds() const { return _messagesFounds.events(); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_messages_search.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "base/qt/qt_compare.h" #include "data/data_message_reaction_id.h" class HistoryItem; class History; class PeerData; namespace Data { struct ReactionId; } // namespace Data namespace Api { enum class SearchFilter { NoFilter, Pinned, }; struct FoundMessages { int total = -1; MessageIdsList messages; QString nextToken; }; class MessagesSearch final { public: struct Request { QString query; PeerData *from = nullptr; std::vector tags; MsgId topMsgId; SearchFilter filter = SearchFilter::NoFilter; friend inline bool operator==( const Request &, const Request &) = default; friend inline auto operator<=>( const Request &, const Request &) = default; }; explicit MessagesSearch(not_null history); ~MessagesSearch(); void searchMessages(Request request); void searchMore(); [[nodiscard]] rpl::producer messagesFounds() const; private: using TLMessages = MTPmessages_Messages; void searchRequest(); void searchReceived( const TLMessages &result, mtpRequestId requestId, const QString &nextToken); const not_null _history; base::flat_map _cacheOfStartByToken; Request _request; MsgId _offsetId; int _searchInHistoryRequest = 0; // Not real mtpRequestId. mtpRequestId _requestId = 0; rpl::event_stream _messagesFounds; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_messages_search_merged.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_messages_search_merged.h" #include "history/history.h" namespace Api { MessagesSearchMerged::MessagesSearchMerged(not_null history) : _apiSearch(history) { if (const auto migrated = history->migrateFrom()) { _migratedSearch.emplace(migrated); } const auto checkWaitingForTotal = [=] { if (_waitingForTotal) { if (_concatedFound.total >= 0 && _migratedFirstFound.total >= 0) { _waitingForTotal = false; _concatedFound.total += _migratedFirstFound.total; _newFounds.fire({}); } } else { _newFounds.fire({}); } }; const auto checkFull = [=](const FoundMessages &data) { if (data.total == int(_concatedFound.messages.size())) { _isFull = true; addFound(_migratedFirstFound); } }; _apiSearch.messagesFounds( ) | rpl::on_next([=](const FoundMessages &data) { if (data.nextToken == _concatedFound.nextToken) { addFound(data); checkFull(data); _nextFounds.fire({}); } else { _concatedFound = data; checkFull(data); checkWaitingForTotal(); } }, _lifetime); if (_migratedSearch) { _migratedSearch->messagesFounds( ) | rpl::on_next([=](const FoundMessages &data) { if (_isFull) { addFound(data); } if (data.nextToken == _migratedFirstFound.nextToken) { _nextFounds.fire({}); } else { _migratedFirstFound = data; checkWaitingForTotal(); } }, _lifetime); } } void MessagesSearchMerged::disableMigrated() { _migratedSearch = std::nullopt; _waitingForTotal = false; _isFull = false; } void MessagesSearchMerged::addFound(const FoundMessages &data) { for (const auto &message : data.messages) { _concatedFound.messages.push_back(message); } } const FoundMessages &MessagesSearchMerged::messages() const { return _concatedFound; } const MessagesSearch::Request &MessagesSearchMerged::request() const { return _request; } void MessagesSearchMerged::clear() { _concatedFound = {}; _migratedFirstFound = {}; _waitingForTotal = false; _isFull = false; } void MessagesSearchMerged::search(const Request &search) { _request = search; _isFull = false; _waitingForTotal = (_migratedSearch != std::nullopt); if (_migratedSearch) { _migratedSearch->searchMessages(search); } _apiSearch.searchMessages(search); } void MessagesSearchMerged::searchMore() { if (_migratedSearch && _isFull) { _migratedSearch->searchMore(); } else { _apiSearch.searchMore(); } } rpl::producer<> MessagesSearchMerged::newFounds() const { return _newFounds.events(); } rpl::producer<> MessagesSearchMerged::nextFounds() const { return _nextFounds.events(); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_messages_search_merged.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "api/api_messages_search.h" class History; class PeerData; namespace Data { struct ReactionId; } // namespace Data namespace Api { // Search in both of history and migrated history, if it exists. class MessagesSearchMerged final { public: using Request = MessagesSearch::Request; using CachedRequests = base::flat_set; MessagesSearchMerged(not_null history); void clear(); void search(const Request &search); void searchMore(); void disableMigrated(); [[nodiscard]] const FoundMessages &messages() const; [[nodiscard]] const Request &request() const; [[nodiscard]] rpl::producer<> newFounds() const; [[nodiscard]] rpl::producer<> nextFounds() const; private: void addFound(const FoundMessages &data); MessagesSearch _apiSearch; Request _request; std::optional _migratedSearch; FoundMessages _migratedFirstFound; FoundMessages _concatedFound; bool _waitingForTotal = false; bool _isFull = false; rpl::event_stream<> _newFounds; rpl::event_stream<> _nextFounds; rpl::lifetime _lifetime; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_peer_colors.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_peer_colors.h" #include "apiwrap.h" #include "data/data_peer.h" #include "window/themes/window_theme.h" #include "ui/chat/chat_style.h" #include "ui/color_int_conversion.h" namespace Api { namespace { constexpr auto kRequestEach = 3600 * crl::time(1000); } // namespace PeerColors::PeerColors(not_null api) : _api(&api->instance()) , _timer([=] { request(); requestProfile(); }) { request(); requestProfile(); _timer.callEach(kRequestEach); } PeerColors::~PeerColors() = default; void PeerColors::request() { if (_requestId) { return; } _requestId = _api.request(MTPhelp_GetPeerColors( MTP_int(_hash) )).done([=](const MTPhelp_PeerColors &result) { _requestId = 0; result.match([&](const MTPDhelp_peerColors &data) { _hash = data.vhash().v; apply(data); }, [](const MTPDhelp_peerColorsNotModified &) { }); }).fail([=] { _requestId = 0; }).send(); } void PeerColors::requestProfile() { if (_profileRequestId) { return; } _profileRequestId = _api.request(MTPhelp_GetPeerProfileColors( MTP_int(_profileHash) )).done([=](const MTPhelp_PeerColors &result) { _profileRequestId = 0; result.match([&](const MTPDhelp_peerColors &data) { _profileHash = data.vhash().v; applyProfile(data); }, [](const MTPDhelp_peerColorsNotModified &) { }); }).fail([=] { _profileRequestId = 0; }).send(); } std::vector PeerColors::suggested() const { return _suggested.current(); } rpl::producer> PeerColors::suggestedValue() const { return _suggested.value(); } auto PeerColors::indicesValue() const -> rpl::producer { return rpl::single( indicesCurrent() ) | rpl::then(_colorIndicesChanged.events() | rpl::map([=] { return indicesCurrent(); })); } Ui::ColorIndicesCompressed PeerColors::indicesCurrent() const { return _colorIndicesCurrent ? *_colorIndicesCurrent : Ui::ColorIndicesCompressed(); } const base::flat_map &PeerColors::requiredLevelsGroup() const { return _requiredLevelsGroup; } const base::flat_map &PeerColors::requiredLevelsChannel() const { return _requiredLevelsChannel; } int PeerColors::requiredLevelFor( PeerId channel, uint8 index, bool isMegagroup, bool profile) const { if (Data::DecideColorIndex(channel) == index) { return 0; } if (profile) { const auto it = _profileColors.find(index); if (it != end(_profileColors)) { return isMegagroup ? it->second.requiredLevelsGroup : it->second.requiredLevelsChannel; } return 1; } const auto &levels = isMegagroup ? _requiredLevelsGroup : _requiredLevelsChannel; if (const auto i = levels.find(index); i != end(levels)) { return i->second; } return 1; } void PeerColors::apply(const MTPDhelp_peerColors &data) { auto suggested = std::vector(); auto colors = std::make_shared< std::array>(); using ParsedColor = std::array; const auto parseColors = [](const MTPhelp_PeerColorSet &set) { return set.match([&](const MTPDhelp_peerColorSet &data) { auto result = ParsedColor(); const auto &list = data.vcolors().v; if (list.empty() || list.size() > Ui::kColorPatternsCount) { LOG(("API Error: Bad count for PeerColorSet.colors: %1" ).arg(list.size())); return ParsedColor(); } auto fill = result.data(); for (const auto &color : list) { *fill++ = (uint32(1) << 24) | uint32(color.v); } return result; }, [](const MTPDhelp_peerColorProfileSet &) { LOG(("API Error: peerColorProfileSet in colors result!")); return ParsedColor(); }); }; const auto &list = data.vcolors().v; _requiredLevelsGroup.clear(); _requiredLevelsChannel.clear(); suggested.reserve(list.size()); for (const auto &color : list) { const auto &data = color.data(); const auto colorIndexBare = data.vcolor_id().v; if (colorIndexBare < 0 || colorIndexBare >= Ui::kColorIndexCount) { LOG(("API Error: Bad color index: %1").arg(colorIndexBare)); continue; } const auto colorIndex = uint8(colorIndexBare); if (const auto min = data.vgroup_min_level()) { _requiredLevelsGroup[colorIndex] = min->v; } if (const auto min = data.vchannel_min_level()) { _requiredLevelsChannel[colorIndex] = min->v; } if (!data.is_hidden()) { suggested.push_back(colorIndex); } if (const auto light = data.vcolors()) { auto &fields = (*colors)[colorIndex]; fields.light = parseColors(*light); if (const auto dark = data.vdark_colors()) { fields.dark = parseColors(*dark); } else { fields.dark = fields.light; } } } if (!_colorIndicesCurrent) { _colorIndicesCurrent = std::make_unique( Ui::ColorIndicesCompressed{ std::move(colors) }); _colorIndicesChanged.fire({}); } else if (*_colorIndicesCurrent->colors != *colors) { _colorIndicesCurrent->colors = std::move(colors); _colorIndicesChanged.fire({}); } _suggested = std::move(suggested); } void PeerColors::applyProfile(const MTPDhelp_peerColors &data) { const auto parseColors = [](const MTPhelp_PeerColorSet &set) { const auto toUint = [](const MTPint &c) { return (uint32(1) << 24) | uint32(c.v); }; return set.match([&](const MTPDhelp_peerColorSet &) { LOG(("API Error: peerColorSet in profile colors result!")); return Data::ColorProfileSet(); }, [&](const MTPDhelp_peerColorProfileSet &data) { auto set = Data::ColorProfileSet(); set.palette.reserve(data.vpalette_colors().v.size()); set.bg.reserve(data.vbg_colors().v.size()); set.story.reserve(data.vstory_colors().v.size()); for (const auto &c : data.vpalette_colors().v) { set.palette.push_back(Ui::ColorFromSerialized(toUint(c))); } for (const auto &c : data.vbg_colors().v) { set.bg.push_back(Ui::ColorFromSerialized(toUint(c))); } for (const auto &c : data.vstory_colors().v) { set.story.push_back(Ui::ColorFromSerialized(toUint(c))); } return set; }); }; auto suggested = std::vector(); const auto &list = data.vcolors().v; suggested.reserve(list.size()); for (const auto &color : list) { const auto &data = color.data(); const auto colorIndexBare = data.vcolor_id().v; if (colorIndexBare < 0 || colorIndexBare >= Ui::kColorIndexCount) { LOG(("API Error: Bad color index: %1").arg(colorIndexBare)); continue; } const auto colorIndex = uint8(colorIndexBare); auto result = ProfileColorOption(); result.isHidden = data.is_hidden(); if (const auto min = data.vgroup_min_level()) { result.requiredLevelsGroup = min->v; } if (const auto min = data.vchannel_min_level()) { result.requiredLevelsChannel = min->v; } if (const auto light = data.vcolors()) { result.data.light = parseColors(*light); } if (const auto dark = data.vdark_colors()) { result.data.dark = parseColors(*dark); } _profileColors[colorIndex] = std::move(result); } } std::optional PeerColors::colorProfileFor( not_null peer) const { if (const auto colorProfileIndex = peer->colorProfileIndex()) { return colorProfileFor(*colorProfileIndex); } return std::nullopt; } std::optional PeerColors::colorProfileFor( uint8 index) const { const auto i = _profileColors.find(index); if (i != end(_profileColors)) { return Window::Theme::IsNightMode() ? i->second.data.dark : i->second.data.light; } return std::nullopt; } std::vector PeerColors::profileColorIndices() const { auto result = std::vector(); result.reserve(_profileColors.size()); for (const auto &[index, option] : _profileColors) { result.push_back(index); } return result; } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_peer_colors.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "base/timer.h" #include "data/data_peer_colors.h" #include "mtproto/sender.h" class ApiWrap; namespace Ui { struct ColorIndicesCompressed; } // namespace Ui namespace Api { class PeerColors final { public: explicit PeerColors(not_null api); ~PeerColors(); [[nodiscard]] std::vector suggested() const; [[nodiscard]] rpl::producer> suggestedValue() const; [[nodiscard]] Ui::ColorIndicesCompressed indicesCurrent() const; [[nodiscard]] auto indicesValue() const -> rpl::producer; [[nodiscard]] auto requiredLevelsGroup() const -> const base::flat_map &; [[nodiscard]] auto requiredLevelsChannel() const -> const base::flat_map &; [[nodiscard]] int requiredLevelFor( PeerId channel, uint8 index, bool isMegagroup, bool profile) const; [[nodiscard]] std::optional colorProfileFor( not_null peer) const; [[nodiscard]] std::optional colorProfileFor( uint8 index) const; [[nodiscard]] std::vector profileColorIndices() const; private: struct ProfileColorOption { Data::ColorProfileData data; int requiredLevelsChannel = 0; int requiredLevelsGroup = 0; bool isHidden = false; }; void request(); void requestProfile(); void apply(const MTPDhelp_peerColors &data); void applyProfile(const MTPDhelp_peerColors &data); MTP::Sender _api; int32 _hash = 0; int32 _profileHash = 0; mtpRequestId _requestId = 0; mtpRequestId _profileRequestId = 0; base::Timer _timer; rpl::variable> _suggested; base::flat_map _requiredLevelsGroup; base::flat_map _requiredLevelsChannel; rpl::event_stream<> _colorIndicesChanged; std::unique_ptr _colorIndicesCurrent; base::flat_map _profileColors; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_peer_photo.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_peer_photo.h" #include "api/api_updates.h" #include "apiwrap.h" #include "base/random.h" #include "base/unixtime.h" #include "data/stickers/data_stickers.h" #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_document.h" #include "data/data_file_origin.h" #include "data/data_peer.h" #include "data/data_photo.h" #include "data/data_session.h" #include "data/data_user.h" #include "data/data_user_photos.h" #include "history/history.h" #include "main/main_session.h" #include "storage/file_upload.h" #include "storage/localimageloader.h" #include "storage/storage_user_photos.h" #include namespace Api { namespace { constexpr auto kSharedMediaLimit = 100; [[nodiscard]] std::shared_ptr PreparePeerPhoto( MTP::DcId dcId, PeerId peerId, QImage &&image) { PreparedPhotoThumbs photoThumbs; QVector photoSizes; QByteArray jpeg; QBuffer jpegBuffer(&jpeg); image.save(&jpegBuffer, "JPG", 87); const auto scaled = [&](int size) { return image.scaled( size, size, Qt::KeepAspectRatio, Qt::SmoothTransformation); }; const auto push = [&]( const char *type, QImage &&image, QByteArray bytes = QByteArray()) { photoSizes.push_back(MTP_photoSize( MTP_string(type), MTP_int(image.width()), MTP_int(image.height()), MTP_int(0))); photoThumbs.emplace(type[0], PreparedPhotoThumb{ .image = std::move(image), .bytes = std::move(bytes) }); }; push("a", scaled(160)); push("b", scaled(320)); push("c", std::move(image), jpeg); const auto id = base::RandomValue(); const auto photo = MTP_photo( MTP_flags(0), MTP_long(id), MTP_long(0), MTP_bytes(), MTP_int(base::unixtime::now()), MTP_vector(photoSizes), MTPVector(), MTP_int(dcId)); auto result = MakePreparedFile({ .id = id, .type = SendMediaType::Photo, }); result->type = SendMediaType::Photo; result->setFileData(jpeg); result->thumbId = id; result->thumbname = "thumb.jpg"; result->photo = photo; result->photoThumbs = photoThumbs; return result; } [[nodiscard]] std::optional PrepareMtpMarkup( not_null session, const PeerPhoto::UserPhoto &d) { const auto &documentId = d.markupDocumentId; const auto &colors = d.markupColors; if (!documentId || colors.empty()) { return std::nullopt; } const auto document = session->data().document(documentId); if (const auto sticker = document->sticker()) { if (sticker->isStatic()) { return std::nullopt; } const auto serializeColor = [](const QColor &color) { return (quint32(std::clamp(color.red(), 0, 255)) << 16) | (quint32(std::clamp(color.green(), 0, 255)) << 8) | quint32(std::clamp(color.blue(), 0, 255)); }; auto mtpColors = QVector(); mtpColors.reserve(colors.size()); ranges::transform( colors, ranges::back_inserter(mtpColors), [&](const QColor &c) { return MTP_int(serializeColor(c)); }); if (sticker->setType == Data::StickersType::Emoji) { return MTP_videoSizeEmojiMarkup( MTP_long(document->id), MTP_vector(mtpColors)); } else if (sticker->set.id && sticker->set.accessHash) { return MTP_videoSizeStickerMarkup( MTP_inputStickerSetID( MTP_long(sticker->set.id), MTP_long(sticker->set.accessHash)), MTP_long(document->id), MTP_vector(mtpColors)); } else if (!sticker->set.shortName.isEmpty()) { return MTP_videoSizeStickerMarkup( MTP_inputStickerSetShortName( MTP_string(sticker->set.shortName)), MTP_long(document->id), MTP_vector(mtpColors)); } else { return MTP_videoSizeEmojiMarkup( MTP_long(document->id), MTP_vector(mtpColors)); } } return std::nullopt; } } // namespace PeerPhoto::PeerPhoto(not_null api) : _session(&api->session()) , _api(&api->instance()) { crl::on_main(_session, [=] { auto &uploader = _session->uploader(); // You can't use _session->lifetime() in the constructor, // only queued, because it is not constructed yet. uploader.photoReady( ) | rpl::on_next([=](const Storage::UploadedMedia &data) { ready(data.fullId, data.info.file, std::nullopt); }, _session->lifetime()); uploader.photoProgress( ) | rpl::on_next([=](const FullMsgId &id) { const auto i = _uploads.find(id); if (i == end(_uploads) || !i->second.photoId) { return; } const auto peer = i->second.peer; const auto photo = _session->data().photo( i->second.photoId); _uploadProgress.fire({ peer, photo->progress() }); }, _session->lifetime()); uploader.photoFailed( ) | rpl::on_next([=](const FullMsgId &id) { const auto i = _uploads.find(id); if (i == end(_uploads)) { return; } const auto peer = i->second.peer; _uploads.erase(i); _uploadFailed.fire_copy(peer); }, _session->lifetime()); }); } void PeerPhoto::upload( not_null peer, UserPhoto &&photo, Fn done) { upload(peer, std::move(photo), UploadType::Default, std::move(done)); } void PeerPhoto::uploadFallback(not_null peer, UserPhoto &&photo) { upload(peer, std::move(photo), UploadType::Fallback, nullptr); } void PeerPhoto::updateSelf( not_null photo, Data::FileOrigin origin, Fn done) { const auto send = [=](auto resend) -> void { const auto usedFileReference = photo->fileReference(); _api.request(MTPphotos_UpdateProfilePhoto( MTP_flags(0), MTPInputUser(), // bot photo->mtpInput() )).done([=](const MTPphotos_Photo &result) { result.match([&](const MTPDphotos_photo &data) { _session->data().processPhoto(data.vphoto()); _session->data().processUsers(data.vusers()); }); if (done) { done(); } }).fail([=](const MTP::Error &error) { if (error.code() == 400 && error.type().startsWith(u"FILE_REFERENCE_"_q)) { photo->session().api().refreshFileReference(origin, [=]( const auto &) { if (photo->fileReference() != usedFileReference) { resend(resend); } }); } }).send(); }; send(send); } void PeerPhoto::upload( not_null peer, UserPhoto &&photo, UploadType type, Fn done) { peer = peer->migrateToOrMe(); const auto mtpMarkup = PrepareMtpMarkup(_session, photo); const auto fakeId = FullMsgId( peer->id, _session->data().nextLocalMessageId()); const auto already = ranges::find( _uploads, peer, [](const auto &pair) { return pair.second.peer; }); if (already != end(_uploads)) { _session->uploader().cancel(already->first); _uploads.erase(already); } const auto &[it, ok] = _uploads.emplace( fakeId, UploadValue{ peer, type, std::move(done), PhotoId(0) }); if (mtpMarkup) { ready(fakeId, std::nullopt, mtpMarkup); } else { const auto prepared = PreparePeerPhoto( _api.instance().mainDcId(), peer->id, base::take(photo.image)); it->second.photoId = prepared->thumbId; _session->uploader().upload(fakeId, prepared); } } void PeerPhoto::suggest(not_null peer, UserPhoto &&photo) { upload(peer, std::move(photo), UploadType::Suggestion, nullptr); } void PeerPhoto::subscribeToUpload( not_null peer, rpl::lifetime &lifetime, UploadCallbacks callbacks) { uploadProgress( ) | rpl::filter([=](const UploadProgress &data) { return (data.peer == peer); }) | rpl::on_next([cb = callbacks.progress](const UploadProgress &data) { if (cb) { cb(data.progress); } }, lifetime); uploadDone( ) | rpl::filter([=](not_null p) { return (p == peer); }) | rpl::on_next([cb = callbacks.done](not_null) { if (cb) { cb(); } }, lifetime); uploadFailed( ) | rpl::filter([=](not_null p) { return (p == peer); }) | rpl::on_next([cb = callbacks.failed](not_null) { if (cb) { cb(); } }, lifetime); } auto PeerPhoto::uploadProgress() const -> rpl::producer { return _uploadProgress.events(); } auto PeerPhoto::uploadDone() const -> rpl::producer> { return _uploadDone.events(); } auto PeerPhoto::uploadFailed() const -> rpl::producer> { return _uploadFailed.events(); } void PeerPhoto::cancelUpload(not_null peer) { peer = peer->migrateToOrMe(); const auto i = ranges::find( _uploads, peer, [](const auto &pair) { return pair.second.peer; }); if (i == end(_uploads)) { return; } const auto fakeId = i->first; _uploads.erase(i); _session->uploader().cancel(fakeId); _uploadFailed.fire_copy(peer); } void PeerPhoto::clear(not_null photo) { const auto self = _session->user(); if (self->userpicPhotoId() == photo->id) { const auto photoId = photo->id; const auto peerId = self->id; _api.request(MTPphotos_UpdateProfilePhoto( MTP_flags(0), MTPInputUser(), // bot MTP_inputPhotoEmpty() )).done([=](const MTPphotos_Photo &result) { self->setPhoto(MTP_userProfilePhotoEmpty()); _session->storage().remove( Storage::UserPhotosRemoveOne(peerToUser(peerId), photoId)); }).send(); } else if (photo->peer && photo->peer->userpicPhotoId() == photo->id) { const auto applier = [=](const MTPUpdates &result) { _session->updates().applyUpdates(result); }; if (const auto chat = photo->peer->asChat()) { _api.request(MTPmessages_EditChatPhoto( chat->inputChat(), MTP_inputChatPhotoEmpty() )).done(applier).send(); } else if (const auto channel = photo->peer->asChannel()) { _api.request(MTPchannels_EditPhoto( channel->inputChannel(), MTP_inputChatPhotoEmpty() )).done(applier).send(); } } else { const auto fallbackPhotoId = SyncUserFallbackPhotoViewer(self); if (fallbackPhotoId && (*fallbackPhotoId) == photo->id) { _api.request(MTPphotos_UpdateProfilePhoto( MTP_flags(MTPphotos_UpdateProfilePhoto::Flag::f_fallback), MTPInputUser(), // bot MTP_inputPhotoEmpty() )).send(); _session->storage().add(Storage::UserPhotosSetBack( peerToUser(self->id), PhotoId())); } else { _api.request(MTPphotos_DeletePhotos( MTP_vector(1, photo->mtpInput()) )).send(); _session->storage().remove(Storage::UserPhotosRemoveOne( peerToUser(self->id), photo->id)); } } } void PeerPhoto::clearPersonal(not_null user) { _api.request(MTPphotos_UploadContactProfilePhoto( MTP_flags(MTPphotos_UploadContactProfilePhoto::Flag::f_save), user->inputUser(), MTPInputFile(), MTPInputFile(), // video MTPdouble(), // video_start_ts MTPVideoSize() // video_emoji_markup )).done([=](const MTPphotos_Photo &result) { result.match([&](const MTPDphotos_photo &data) { _session->data().processPhoto(data.vphoto()); _session->data().processUsers(data.vusers()); }); }).send(); if (!user->userpicPhotoUnknown() && user->hasPersonalPhoto()) { _session->storage().remove(Storage::UserPhotosRemoveOne( peerToUser(user->id), user->userpicPhotoId())); } } void PeerPhoto::set(not_null peer, not_null photo) { if (peer->userpicPhotoId() == photo->id) { return; } if (peer == _session->user()) { const auto photoId = photo->id; const auto peerId = peer->id; _api.request(MTPphotos_UpdateProfilePhoto( MTP_flags(0), MTPInputUser(), // bot photo->mtpInput() )).done([=](const MTPphotos_Photo &result) { const auto newPhoto = _session->data().processPhoto( result.data().vphoto()); _session->data().processUsers(result.data().vusers()); _session->storage().replace(Storage::UserPhotosReplace( peerToUser(peerId), photoId, newPhoto->id)); }).send(); } else { const auto applier = [=](const MTPUpdates &result) { _session->updates().applyUpdates(result); }; if (const auto chat = peer->asChat()) { _api.request(MTPmessages_EditChatPhoto( chat->inputChat(), MTP_inputChatPhoto(photo->mtpInput()) )).done(applier).send(); } else if (const auto channel = peer->asChannel()) { _api.request(MTPchannels_EditPhoto( channel->inputChannel(), MTP_inputChatPhoto(photo->mtpInput()) )).done(applier).send(); } } } void PeerPhoto::ready( const FullMsgId &msgId, std::optional file, std::optional videoSize) { const auto maybeUploadValue = _uploads.take(msgId); if (!maybeUploadValue) { return; } const auto peer = maybeUploadValue->peer; const auto type = maybeUploadValue->type; const auto done = maybeUploadValue->done; const auto finish = [=] { _uploadDone.fire_copy(peer); if (done) { done(); } }; const auto fail = [=](const MTP::Error &error) { _uploadFailed.fire_copy(peer); }; const auto applier = [=](const MTPUpdates &result) { _session->updates().applyUpdates(result); finish(); }; const auto botUserInput = [&] { const auto user = peer->asUser(); return (user && user->botInfo && user->botInfo->canEditInformation) ? std::make_optional(user->inputUser()) : std::nullopt; }(); if (peer->isSelf() || botUserInput) { using Flag = MTPphotos_UploadProfilePhoto::Flag; const auto none = MTPphotos_UploadProfilePhoto::Flags(0); _api.request(MTPphotos_UploadProfilePhoto( MTP_flags((file ? Flag::f_file : none) | (botUserInput ? Flag::f_bot : none) | (videoSize ? Flag::f_video_emoji_markup : none) | ((type == UploadType::Fallback) ? Flag::f_fallback : none)), botUserInput ? (*botUserInput) : MTPInputUser(), // bot file ? (*file) : MTPInputFile(), MTPInputFile(), // video MTPdouble(), // video_start_ts videoSize ? (*videoSize) : MTPVideoSize() // video_emoji_markup )).done([=](const MTPphotos_Photo &result) { const auto photoId = _session->data().processPhoto( result.data().vphoto())->id; _session->data().processUsers(result.data().vusers()); if (type == UploadType::Fallback) { _session->storage().add(Storage::UserPhotosSetBack( peerToUser(peer->id), photoId)); } else { _session->storage().add(Storage::UserPhotosAddNew( peerToUser(peer->id), photoId)); } finish(); }).fail(fail).send(); } else if (const auto chat = peer->asChat()) { const auto history = _session->data().history(chat); using Flag = MTPDinputChatUploadedPhoto::Flag; const auto none = MTPDinputChatUploadedPhoto::Flags(0); history->sendRequestId = _api.request(MTPmessages_EditChatPhoto( chat->inputChat(), MTP_inputChatUploadedPhoto( MTP_flags((file ? Flag::f_file : none) | (videoSize ? Flag::f_video_emoji_markup : none)), file ? (*file) : MTPInputFile(), MTPInputFile(), // video MTPdouble(), // video_start_ts videoSize ? (*videoSize) : MTPVideoSize()) // video_emoji_markup )).done(applier).fail(fail).afterRequest(history->sendRequestId).send(); } else if (const auto channel = peer->asChannel()) { using Flag = MTPDinputChatUploadedPhoto::Flag; const auto none = MTPDinputChatUploadedPhoto::Flags(0); const auto history = _session->data().history(channel); history->sendRequestId = _api.request(MTPchannels_EditPhoto( channel->inputChannel(), MTP_inputChatUploadedPhoto( MTP_flags((file ? Flag::f_file : none) | (videoSize ? Flag::f_video_emoji_markup : none)), file ? (*file) : MTPInputFile(), MTPInputFile(), // video MTPdouble(), // video_start_ts videoSize ? (*videoSize) : MTPVideoSize()) // video_emoji_markup )).done(applier).fail(fail).afterRequest(history->sendRequestId).send(); } else if (const auto user = peer->asUser()) { using Flag = MTPphotos_UploadContactProfilePhoto::Flag; const auto none = MTPphotos_UploadContactProfilePhoto::Flags(0); _api.request(MTPphotos_UploadContactProfilePhoto( MTP_flags((file ? Flag::f_file : none) | (videoSize ? Flag::f_video_emoji_markup : none) | ((type == UploadType::Suggestion) ? Flag::f_suggest : Flag::f_save)), user->inputUser(), file ? (*file) : MTPInputFile(), MTPInputFile(), // video MTPdouble(), // video_start_ts videoSize ? (*videoSize) : MTPVideoSize() // video_emoji_markup )).done([=](const MTPphotos_Photo &result) { result.match([&](const MTPDphotos_photo &data) { _session->data().processPhoto(data.vphoto()); _session->data().processUsers(data.vusers()); }); if (type != UploadType::Suggestion) { user->updateFullForced(); } finish(); }).fail(fail).send(); } } void PeerPhoto::requestUserPhotos( not_null user, UserPhotoId afterId) { if (_userPhotosRequests.contains(user)) { return; } const auto requestId = _api.request(MTPphotos_GetUserPhotos( user->inputUser(), MTP_int(0), MTP_long(afterId), MTP_int(kSharedMediaLimit) )).done([this, user](const MTPphotos_Photos &result) { _userPhotosRequests.remove(user); auto fullCount = result.match([](const MTPDphotos_photos &d) { return int(d.vphotos().v.size()); }, [](const MTPDphotos_photosSlice &d) { return d.vcount().v; }); auto &owner = _session->data(); auto photoIds = result.match([&](const auto &data) { owner.processUsers(data.vusers()); auto photoIds = std::vector(); photoIds.reserve(data.vphotos().v.size()); for (const auto &single : data.vphotos().v) { const auto photo = owner.processPhoto(single); if (!photo->isNull()) { photoIds.push_back(photo->id); } } return photoIds; }); if (!user->userpicPhotoUnknown() && user->hasPersonalPhoto()) { const auto photo = owner.photo(user->userpicPhotoId()); if (!photo->isNull()) { ++fullCount; photoIds.insert(begin(photoIds), photo->id); } } _session->storage().add(Storage::UserPhotosAddSlice( peerToUser(user->id), std::move(photoIds), fullCount )); }).fail([this, user] { _userPhotosRequests.remove(user); }).send(); _userPhotosRequests.emplace(user, requestId); } auto PeerPhoto::emojiList(EmojiListType type) -> EmojiListData & { switch (type) { case EmojiListType::Profile: return _profileEmojiList; case EmojiListType::Group: return _groupEmojiList; case EmojiListType::Background: return _backgroundEmojiList; case EmojiListType::NoChannelStatus: return _noChannelStatusEmojiList; } Unexpected("Type in PeerPhoto::emojiList."); } auto PeerPhoto::emojiList(EmojiListType type) const -> const EmojiListData & { return const_cast(this)->emojiList(type); } void PeerPhoto::requestEmojiList(EmojiListType type) { auto &list = emojiList(type); if (list.requestId) { return; } const auto send = [&](auto &&request) { return _api.request( std::move(request) ).done([=](const MTPEmojiList &result) { auto &list = emojiList(type); list.requestId = 0; result.match([](const MTPDemojiListNotModified &data) { }, [&](const MTPDemojiList &data) { list.list = ranges::views::all( data.vdocument_id().v ) | ranges::views::transform( &MTPlong::v ) | ranges::to_vector; }); }).fail([=] { emojiList(type).requestId = 0; }).send(); }; list.requestId = (type == EmojiListType::Profile) ? send(MTPaccount_GetDefaultProfilePhotoEmojis()) : (type == EmojiListType::Group) ? send(MTPaccount_GetDefaultGroupPhotoEmojis()) : (type == EmojiListType::NoChannelStatus) ? send(MTPaccount_GetChannelRestrictedStatusEmojis()) : send(MTPaccount_GetDefaultBackgroundEmojis()); } rpl::producer PeerPhoto::emojiListValue( EmojiListType type) { auto &list = emojiList(type); if (list.list.current().empty() && !list.requestId) { requestEmojiList(type); } return list.list.value(); } // Non-personal photo in case a personal photo is set. void PeerPhoto::registerNonPersonalPhoto( not_null user, not_null photo) { _nonPersonalPhotos.emplace_or_assign(user, photo); } void PeerPhoto::unregisterNonPersonalPhoto(not_null user) { _nonPersonalPhotos.erase(user); } PhotoData *PeerPhoto::nonPersonalPhoto( not_null user) const { const auto i = _nonPersonalPhotos.find(user); return (i != end(_nonPersonalPhotos)) ? i->second.get() : nullptr; } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_peer_photo.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "mtproto/sender.h" class ApiWrap; class PeerData; class UserData; namespace Data { struct FileOrigin; } // namespace Data namespace Main { class Session; } // namespace Main namespace Api { class PeerPhoto final { public: using UserPhotoId = PhotoId; explicit PeerPhoto(not_null api); enum class EmojiListType { Profile, Group, Background, NoChannelStatus, }; struct UserPhoto { QImage image; DocumentId markupDocumentId = 0; std::vector markupColors; }; struct UploadProgress { not_null peer; float64 progress = 0.; }; void upload( not_null peer, UserPhoto &&photo, Fn done = nullptr); void uploadFallback(not_null peer, UserPhoto &&photo); void updateSelf( not_null photo, Data::FileOrigin origin, Fn done = nullptr); void suggest(not_null peer, UserPhoto &&photo); void clear(not_null photo); void clearPersonal(not_null user); void set(not_null peer, not_null photo); struct UploadCallbacks { Fn progress; Fn done; Fn failed; }; void subscribeToUpload( not_null peer, rpl::lifetime &lifetime, UploadCallbacks callbacks); [[nodiscard]] auto uploadProgress() const -> rpl::producer; [[nodiscard]] auto uploadDone() const -> rpl::producer>; [[nodiscard]] auto uploadFailed() const -> rpl::producer>; void cancelUpload(not_null peer); void requestUserPhotos(not_null user, UserPhotoId afterId); void requestEmojiList(EmojiListType type); using EmojiList = std::vector; [[nodiscard]] rpl::producer emojiListValue(EmojiListType type); // Non-personal photo in case a personal photo is set. void registerNonPersonalPhoto( not_null user, not_null photo); void unregisterNonPersonalPhoto(not_null user); [[nodiscard]] PhotoData *nonPersonalPhoto( not_null user) const; private: enum class UploadType { Default, Suggestion, Fallback, }; struct EmojiListData { rpl::variable list; mtpRequestId requestId = 0; }; void ready( const FullMsgId &msgId, std::optional file, std::optional videoSize); void upload( not_null peer, UserPhoto &&photo, UploadType type, Fn done); [[nodiscard]] EmojiListData &emojiList(EmojiListType type); [[nodiscard]] const EmojiListData &emojiList(EmojiListType type) const; const not_null _session; MTP::Sender _api; struct UploadValue { not_null peer; UploadType type = UploadType::Default; Fn done; PhotoId photoId = 0; }; base::flat_map _uploads; rpl::event_stream _uploadProgress; rpl::event_stream> _uploadDone; rpl::event_stream> _uploadFailed; base::flat_map, mtpRequestId> _userPhotosRequests; base::flat_map< not_null, not_null> _nonPersonalPhotos; EmojiListData _profileEmojiList; EmojiListData _groupEmojiList; EmojiListData _backgroundEmojiList; EmojiListData _noChannelStatusEmojiList; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_peer_search.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_peer_search.h" #include "api/api_single_message_search.h" #include "apiwrap.h" #include "data/data_session.h" #include "dialogs/ui/chat_search_in.h" // IsHashOrCashtagSearchQuery #include "main/main_session.h" namespace Api { namespace { constexpr auto kMinSponsoredQueryLength = 4; } // namespace PeerSearch::PeerSearch(not_null session, Type type) : _session(session) , _type(type) { } PeerSearch::~PeerSearch() { clear(); } void PeerSearch::request( const QString &query, Fn callback, RequestType type) { using namespace Dialogs; _query = Api::ConvertPeerSearchQuery(query); _callback = callback; if (_query.isEmpty() || IsHashOrCashtagSearchQuery(_query) != HashOrCashtag::None) { finish(PeerSearchResult{}); return; } auto &cache = _cache[_query]; if (cache.peersReady && cache.sponsoredReady) { finish(cache.result); return; } else if (type == RequestType::CacheOnly) { _callback = nullptr; return; } else if (cache.requested) { return; } cache.requested = true; cache.result.query = _query; if (_query.size() < kMinSponsoredQueryLength) { cache.sponsoredReady = true; } else if (_type == Type::WithSponsored) { requestSponsored(); } requestPeers(); } void PeerSearch::requestPeers() { const auto requestId = _session->api().request(MTPcontacts_Search( MTP_string(_query), MTP_int(SearchPeopleLimit) )).done([=](const MTPcontacts_Found &result, mtpRequestId requestId) { const auto &data = result.data(); _session->data().processUsers(data.vusers()); _session->data().processChats(data.vchats()); auto parsed = PeerSearchResult(); parsed.my.reserve(data.vmy_results().v.size()); for (const auto &id : data.vmy_results().v) { const auto peerId = peerFromMTP(id); parsed.my.push_back(_session->data().peer(peerId)); } parsed.peers.reserve(data.vresults().v.size()); for (const auto &id : data.vresults().v) { const auto peerId = peerFromMTP(id); parsed.peers.push_back(_session->data().peer(peerId)); } finishPeers(requestId, std::move(parsed)); }).fail([=](const MTP::Error &error, mtpRequestId requestId) { finishPeers(requestId, PeerSearchResult{}); }).send(); _peerRequests.emplace(requestId, _query); } void PeerSearch::requestSponsored() { const auto requestId = _session->api().request( MTPcontacts_GetSponsoredPeers(MTP_string(_query)) ).done([=]( const MTPcontacts_SponsoredPeers &result, mtpRequestId requestId) { result.match([&](const MTPDcontacts_sponsoredPeersEmpty &) { finishSponsored(requestId, PeerSearchResult{}); }, [&](const MTPDcontacts_sponsoredPeers &data) { _session->data().processUsers(data.vusers()); _session->data().processChats(data.vchats()); auto parsed = PeerSearchResult(); parsed.sponsored.reserve(data.vpeers().v.size()); for (const auto &peer : data.vpeers().v) { const auto &data = peer.data(); const auto peerId = peerFromMTP(data.vpeer()); parsed.sponsored.push_back({ .peer = _session->data().peer(peerId), .randomId = data.vrandom_id().v, .sponsorInfo = TextWithEntities::Simple( qs(data.vsponsor_info().value_or_empty())), .additionalInfo = TextWithEntities::Simple( qs(data.vadditional_info().value_or_empty())), }); } finishSponsored(requestId, std::move(parsed)); }); }).fail([=](const MTP::Error &error, mtpRequestId requestId) { finishSponsored(requestId, PeerSearchResult{}); }).send(); _sponsoredRequests.emplace(requestId, _query); } void PeerSearch::finishPeers( mtpRequestId requestId, PeerSearchResult result) { const auto query = _peerRequests.take(requestId); Assert(query.has_value()); auto &cache = _cache[*query]; cache.peersReady = true; cache.result.my = std::move(result.my); cache.result.peers = std::move(result.peers); if (cache.sponsoredReady && _query == *query) { finish(cache.result); } } void PeerSearch::finishSponsored( mtpRequestId requestId, PeerSearchResult result) { const auto query = _sponsoredRequests.take(requestId); Assert(query.has_value()); auto &cache = _cache[*query]; cache.sponsoredReady = true; cache.result.sponsored = std::move(result.sponsored); if (cache.peersReady && _query == *query) { finish(cache.result); } } void PeerSearch::finish(PeerSearchResult result) { if (const auto onstack = base::take(_callback)) { onstack(std::move(result)); } } void PeerSearch::clear() { _query = QString(); _callback = nullptr; _cache.clear(); for (const auto &[requestId, query] : base::take(_peerRequests)) { _session->api().request(requestId).cancel(); } for (const auto &[requestId, query] : base::take(_sponsoredRequests)) { _session->api().request(requestId).cancel(); } } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_peer_search.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once namespace Main { class Session; } // namespace Main namespace Api { struct SponsoredSearchResult { not_null peer; QByteArray randomId; TextWithEntities sponsorInfo; TextWithEntities additionalInfo; }; struct PeerSearchResult { QString query; std::vector> my; std::vector> peers; std::vector sponsored; }; class PeerSearch final { public: enum class Type { WithSponsored, JustPeers, }; PeerSearch(not_null session, Type type); ~PeerSearch(); enum class RequestType { CacheOnly, CacheOrRemote, }; void request( const QString &query, Fn callback, RequestType type = RequestType::CacheOrRemote); void clear(); private: struct CacheEntry { PeerSearchResult result; bool requested = false; bool peersReady = false; bool sponsoredReady = false; }; void requestPeers(); void requestSponsored(); void finish(PeerSearchResult result); void finishPeers(mtpRequestId requestId, PeerSearchResult result); void finishSponsored(mtpRequestId requestId, PeerSearchResult result); const not_null _session; const Type _type; QString _query; Fn _callback; base::flat_map _cache; base::flat_map _peerRequests; base::flat_map _sponsoredRequests; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_polls.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_polls.h" #include "api/api_common.h" #include "api/api_text_entities.h" #include "api/api_updates.h" #include "apiwrap.h" #include "base/random.h" #include "data/business/data_shortcut_messages.h" #include "data/data_changes.h" #include "data/data_histories.h" #include "data/data_poll.h" #include "data/data_session.h" #include "history/history.h" #include "history/history_item.h" #include "history/history_item_helpers.h" // ShouldSendSilent #include "main/main_session.h" namespace Api { Polls::Polls(not_null api) : _session(&api->session()) , _api(&api->instance()) { } void Polls::create( const PollData &data, const TextWithEntities &text, SendAction action, Fn done, Fn fail) { _session->api().sendAction(action); const auto history = action.history; const auto peer = history->peer; const auto topicRootId = action.replyTo.messageId ? action.replyTo.topicRootId : 0; const auto monoforumPeerId = action.replyTo.monoforumPeerId; auto sendFlags = MTPmessages_SendMedia::Flags(0); if (action.replyTo) { sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to; } const auto clearCloudDraft = action.clearDraft; if (clearCloudDraft) { sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft; history->clearLocalDraft(topicRootId, monoforumPeerId); history->clearCloudDraft(topicRootId, monoforumPeerId); history->startSavingCloudDraft(topicRootId, monoforumPeerId); } const auto silentPost = ShouldSendSilent(peer, action.options); const auto starsPaid = std::min( peer->starsPerMessageChecked(), action.options.starsApproved); if (silentPost) { sendFlags |= MTPmessages_SendMedia::Flag::f_silent; } if (action.options.scheduled) { sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date; if (action.options.scheduleRepeatPeriod) { sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_repeat_period; } } if (action.options.shortcutId) { sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut; } if (action.options.effectId) { sendFlags |= MTPmessages_SendMedia::Flag::f_effect; } if (action.options.suggest) { sendFlags |= MTPmessages_SendMedia::Flag::f_suggested_post; } if (starsPaid) { action.options.starsApproved -= starsPaid; sendFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars; } const auto sendAs = action.options.sendAs; if (sendAs) { sendFlags |= MTPmessages_SendMedia::Flag::f_send_as; } auto sentEntities = Api::EntitiesToMTP( _session, text.entities, Api::ConvertOption::SkipLocal); if (!sentEntities.v.isEmpty()) { sendFlags |= MTPmessages_SendMedia::Flag::f_entities; } auto &histories = history->owner().histories(); const auto randomId = base::RandomValue(); histories.sendPreparedMessage( history, action.replyTo, randomId, Data::Histories::PrepareMessage( MTP_flags(sendFlags), peer->input(), Data::Histories::ReplyToPlaceholder(), PollDataToInputMedia(&data), MTP_string(text.text), MTP_long(randomId), MTPReplyMarkup(), sentEntities, MTP_int(action.options.scheduled), MTP_int(action.options.scheduleRepeatPeriod), (sendAs ? sendAs->input() : MTP_inputPeerEmpty()), Data::ShortcutIdToMTP(_session, action.options.shortcutId), MTP_long(action.options.effectId), MTP_long(starsPaid), SuggestToMTP(action.options.suggest) ), [=](const MTPUpdates &result, const MTP::Response &response) { if (clearCloudDraft) { history->finishSavingCloudDraft( topicRootId, monoforumPeerId, UnixtimeFromMsgId(response.outerMsgId)); } _session->changes().historyUpdated( history, (action.options.scheduled ? Data::HistoryUpdate::Flag::ScheduledSent : Data::HistoryUpdate::Flag::MessageSent)); done(); }, [=](const MTP::Error &error, const MTP::Response &response) { if (clearCloudDraft) { history->finishSavingCloudDraft( topicRootId, monoforumPeerId, UnixtimeFromMsgId(response.outerMsgId)); } const auto expired = (error.code() == 400) && error.type().startsWith(u"FILE_REFERENCE_"_q); fail(expired); }); } void Polls::sendVotes( FullMsgId itemId, const std::vector &options) { if (_pollVotesRequestIds.contains(itemId)) { return; } const auto item = _session->data().message(itemId); const auto media = item ? item->media() : nullptr; const auto poll = media ? media->poll() : nullptr; if (!item) { return; } const auto showSending = poll && !options.empty(); const auto hideSending = [=] { if (showSending) { if (const auto item = _session->data().message(itemId)) { poll->sendingVotes.clear(); _session->data().requestItemRepaint(item); } } }; if (showSending) { poll->sendingVotes = options; _session->data().requestItemRepaint(item); } auto prepared = QVector(); prepared.reserve(options.size()); ranges::transform( options, ranges::back_inserter(prepared), [](const QByteArray &option) { return MTP_bytes(option); }); const auto requestId = _api.request(MTPmessages_SendVote( item->history()->peer->input(), MTP_int(item->id), MTP_vector(prepared) )).done([=](const MTPUpdates &result) { _pollVotesRequestIds.erase(itemId); hideSending(); _session->updates().applyUpdates(result); }).fail([=] { _pollVotesRequestIds.erase(itemId); hideSending(); }).send(); _pollVotesRequestIds.emplace(itemId, requestId); } void Polls::addAnswer( FullMsgId itemId, const TextWithEntities &text, const PollMedia &media, Fn done, Fn fail) { if (_pollAddAnswerRequestIds.contains(itemId)) { return; } const auto item = _session->data().message(itemId); if (!item) { return; } const auto sentEntities = Api::EntitiesToMTP( _session, text.entities, Api::ConvertOption::SkipLocal); using Flag = MTPDinputPollAnswer::Flag; const auto flags = media ? Flag::f_media : Flag(); const auto answer = MTP_inputPollAnswer( MTP_flags(flags), MTP_textWithEntities( MTP_string(text.text), sentEntities), media ? PollMediaToMTP(media) : MTPInputMedia()); const auto requestId = _api.request(MTPmessages_AddPollAnswer( item->history()->peer->input(), MTP_int(item->id), answer )).done([=](const MTPUpdates &result) { _pollAddAnswerRequestIds.erase(itemId); _session->updates().applyUpdates(result); if (done) { done(); } }).fail([=](const MTP::Error &error) { _pollAddAnswerRequestIds.erase(itemId); if (fail) { fail(error.type()); } }).send(); _pollAddAnswerRequestIds.emplace(itemId, requestId); } void Polls::deleteAnswer(FullMsgId itemId, const QByteArray &option) { if (_pollVotesRequestIds.contains(itemId)) { return; } const auto item = _session->data().message(itemId); if (!item) { return; } const auto requestId = _api.request(MTPmessages_DeletePollAnswer( item->history()->peer->input(), MTP_int(item->id), MTP_bytes(option) )).done([=](const MTPUpdates &result) { _pollVotesRequestIds.erase(itemId); _session->updates().applyUpdates(result); }).fail([=] { _pollVotesRequestIds.erase(itemId); }).send(); _pollVotesRequestIds.emplace(itemId, requestId); } void Polls::close(not_null item) { const auto itemId = item->fullId(); if (_pollCloseRequestIds.contains(itemId)) { return; } const auto media = item ? item->media() : nullptr; const auto poll = media ? media->poll() : nullptr; if (!poll) { return; } const auto requestId = _api.request(MTPmessages_EditMessage( MTP_flags(MTPmessages_EditMessage::Flag::f_media), item->history()->peer->input(), MTP_int(item->id), MTPstring(), PollDataToInputMedia(poll, true), MTPReplyMarkup(), MTPVector(), MTP_int(0), // schedule_date MTP_int(0), // schedule_repeat_period MTPint() // quick_reply_shortcut_id )).done([=](const MTPUpdates &result) { _pollCloseRequestIds.erase(itemId); _session->updates().applyUpdates(result); }).fail([=] { _pollCloseRequestIds.erase(itemId); }).send(); _pollCloseRequestIds.emplace(itemId, requestId); } void Polls::reloadResults(not_null item) { const auto itemId = item->fullId(); if (!item->isRegular() || _pollReloadRequestIds.contains(itemId)) { return; } const auto media = item->media(); const auto poll = media ? media->poll() : nullptr; const auto pollHash = poll ? poll->hash : uint64(0); const auto requestId = _api.request(MTPmessages_GetPollResults( item->history()->peer->input(), MTP_int(item->id), MTP_long(pollHash) )).done([=](const MTPUpdates &result) { _pollReloadRequestIds.erase(itemId); _session->updates().applyUpdates(result); }).fail([=] { _pollReloadRequestIds.erase(itemId); }).send(); _pollReloadRequestIds.emplace(itemId, requestId); } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_polls.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "mtproto/sender.h" #include "ui/text/text_entity.h" class ApiWrap; class HistoryItem; struct PollData; struct PollMedia; namespace Main { class Session; } // namespace Main namespace Api { struct SendAction; class Polls final { public: explicit Polls(not_null api); void create( const PollData &data, const TextWithEntities &text, SendAction action, Fn done, Fn fail); void sendVotes( FullMsgId itemId, const std::vector &options); void addAnswer( FullMsgId itemId, const TextWithEntities &text, const PollMedia &media, Fn done, Fn fail); void deleteAnswer(FullMsgId itemId, const QByteArray &option); void close(not_null item); void reloadResults(not_null item); private: const not_null _session; MTP::Sender _api; base::flat_map _pollVotesRequestIds; base::flat_map _pollAddAnswerRequestIds; base::flat_map _pollCloseRequestIds; base::flat_map _pollReloadRequestIds; }; } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_premium.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_premium.h" #include "api/api_premium_option.h" #include "api/api_text_entities.h" #include "apiwrap.h" #include "base/random.h" #include "data/data_channel.h" #include "data/data_document.h" #include "data/data_peer.h" #include "data/data_peer_values.h" #include "data/data_session.h" #include "data/data_user.h" #include "history/view/history_view_element.h" #include "history/history.h" #include "history/history_item.h" #include "main/main_app_config.h" #include "main/main_session.h" #include "payments/payments_form.h" #include "ui/chat/chat_style.h" // ColorCollectible #include "ui/text/format_values.h" namespace Api { namespace { [[nodiscard]] GiftCode Parse(const MTPDpayments_checkedGiftCode &data) { return { .from = data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId(), .to = data.vto_id() ? peerFromUser(*data.vto_id()) : PeerId(), .giveawayId = data.vgiveaway_msg_id().value_or_empty(), .date = data.vdate().v, .used = data.vused_date().value_or_empty(), .days = data.vdays().v, .giveaway = data.is_via_giveaway(), }; } [[nodiscard]] Data::PremiumSubscriptionOptions GiftCodesFromTL( const QVector &tlOptions) { auto options = PremiumSubscriptionOptionsFromTL(tlOptions); for (auto i = 0; i < options.size(); i++) { const auto &tlOption = tlOptions[i].data(); const auto currency = qs(tlOption.vcurrency()); const auto perUserText = Ui::FillAmountAndCurrency( tlOption.vamount().v / float64(tlOption.vusers().v), currency, false); options[i].costPerMonth = perUserText + ' ' + QChar(0x00D7) + ' ' + QString::number(tlOption.vusers().v); options[i].total = Ui::FillAmountAndCurrency( tlOption.vamount().v, currency); options[i].currency = currency; } return options; } [[nodiscard]] int FindStarsForResale(const MTPVector *list) { if (!list) { return 0; } for (const auto &amount : list->v) { if (amount.type() == mtpc_starsAmount) { return int(amount.c_starsAmount().vamount().v); } } return 0; } [[nodiscard]] int64 FindTonForResale(const MTPVector *list) { if (!list) { return 0; } for (const auto &amount : list->v) { if (amount.type() == mtpc_starsTonAmount) { return int64(amount.c_starsTonAmount().vamount().v); } } return 0; } } // namespace Premium::Premium(not_null api) : _session(&api->session()) , _api(&api->instance()) { crl::on_main(_session, [=] { // You can't use _session->user() in the constructor, // only queued, because it is not constructed yet. Data::AmPremiumValue( _session ) | rpl::on_next([=] { reload(); if (_session->premium()) { reloadCloudSet(); } }, _session->lifetime()); }); } rpl::producer Premium::statusTextValue() const { return _statusTextUpdates.events_starting_with_copy( _statusText.value_or(TextWithEntities())); } auto Premium::videos() const -> const base::flat_map> & { return _videos; } rpl::producer<> Premium::videosUpdated() const { return _videosUpdated.events(); } auto Premium::stickers() const -> const std::vector> & { return _stickers; } rpl::producer<> Premium::stickersUpdated() const { return _stickersUpdated.events(); } auto Premium::cloudSet() const -> const std::vector> & { return _cloudSet; } rpl::producer<> Premium::cloudSetUpdated() const { return _cloudSetUpdated.events(); } auto Premium::helloStickers() const -> const std::vector> & { if (_helloStickers.empty()) { const_cast(this)->reloadHelloStickers(); } return _helloStickers; } rpl::producer<> Premium::helloStickersUpdated() const { return _helloStickersUpdated.events(); } int64 Premium::monthlyAmount() const { return _monthlyAmount; } QString Premium::monthlyCurrency() const { return _monthlyCurrency; } void Premium::reload() { reloadPromo(); reloadStickers(); } void Premium::reloadPromo() { if (_promoRequestId) { return; } _promoRequestId = _api.request(MTPhelp_GetPremiumPromo( )).done([=](const MTPhelp_PremiumPromo &result) { _promoRequestId = 0; const auto &data = result.data(); _session->data().processUsers(data.vusers()); _subscriptionOptions = PremiumSubscriptionOptionsFromTL( data.vperiod_options().v); for (const auto &option : data.vperiod_options().v) { if (option.data().vmonths().v == 1) { _monthlyAmount = option.data().vamount().v; _monthlyCurrency = qs(option.data().vcurrency()); } } auto text = TextWithEntities{ qs(data.vstatus_text()), EntitiesFromMTP(_session, data.vstatus_entities().v), }; _statusText = text; _statusTextUpdates.fire(std::move(text)); auto videos = base::flat_map>(); const auto count = int(std::min( data.vvideo_sections().v.size(), data.vvideos().v.size())); videos.reserve(count); for (auto i = 0; i != count; ++i) { const auto document = _session->data().processDocument( data.vvideos().v[i]); if ((!document->isVideoFile() && !document->isGifv()) || !document->supportsStreaming()) { document->forceIsStreamedAnimation(); } videos.emplace( qs(data.vvideo_sections().v[i]), document); } if (_videos != videos) { _videos = std::move(videos); _videosUpdated.fire({}); } }).fail([=] { _promoRequestId = 0; }).send(); } void Premium::reloadStickers() { if (_stickersRequestId) { return; } _stickersRequestId = _api.request(MTPmessages_GetStickers( MTP_string("\xe2\xad\x90\xef\xb8\x8f\xe2\xad\x90\xef\xb8\x8f"), MTP_long(_stickersHash) )).done([=](const MTPmessages_Stickers &result) { _stickersRequestId = 0; result.match([&](const MTPDmessages_stickersNotModified &) { }, [&](const MTPDmessages_stickers &data) { _stickersHash = data.vhash().v; const auto owner = &_session->data(); _stickers.clear(); for (const auto &sticker : data.vstickers().v) { const auto document = owner->processDocument(sticker); if (document->isPremiumSticker()) { _stickers.push_back(document); } } _stickersUpdated.fire({}); }); }).fail([=] { _stickersRequestId = 0; }).send(); } void Premium::reloadCloudSet() { if (_cloudSetRequestId) { return; } _cloudSetRequestId = _api.request(MTPmessages_GetStickers( MTP_string("\xf0\x9f\x93\x82\xe2\xad\x90\xef\xb8\x8f"), MTP_long(_cloudSetHash) )).done([=](const MTPmessages_Stickers &result) { _cloudSetRequestId = 0; result.match([&](const MTPDmessages_stickersNotModified &) { }, [&](const MTPDmessages_stickers &data) { _cloudSetHash = data.vhash().v; const auto owner = &_session->data(); _cloudSet.clear(); for (const auto &sticker : data.vstickers().v) { const auto document = owner->processDocument(sticker); if (document->isPremiumSticker()) { _cloudSet.push_back(document); } } _cloudSetUpdated.fire({}); }); }).fail([=] { _cloudSetRequestId = 0; }).send(); } void Premium::reloadHelloStickers() { if (_helloStickersRequestId) { return; } _helloStickersRequestId = _api.request(MTPmessages_GetStickers( MTP_string("\xf0\x9f\x91\x8b\xe2\xad\x90\xef\xb8\x8f"), MTP_long(_helloStickersHash) )).done([=](const MTPmessages_Stickers &result) { _helloStickersRequestId = 0; result.match([&](const MTPDmessages_stickersNotModified &) { }, [&](const MTPDmessages_stickers &data) { _helloStickersHash = data.vhash().v; const auto owner = &_session->data(); _helloStickers.clear(); for (const auto &sticker : data.vstickers().v) { const auto document = owner->processDocument(sticker); if (document->sticker()) { _helloStickers.push_back(document); } } _helloStickersUpdated.fire({}); }); }).fail([=] { _helloStickersRequestId = 0; }).send(); } void Premium::checkGiftCode( const QString &slug, Fn done) { if (_giftCodeRequestId) { if (_giftCodeSlug == slug) { return; } _api.request(_giftCodeRequestId).cancel(); } _giftCodeSlug = slug; _giftCodeRequestId = _api.request(MTPpayments_CheckGiftCode( MTP_string(slug) )).done([=](const MTPpayments_CheckedGiftCode &result) { _giftCodeRequestId = 0; const auto &data = result.data(); _session->data().processUsers(data.vusers()); _session->data().processChats(data.vchats()); done(updateGiftCode(slug, Parse(data))); }).fail([=](const MTP::Error &error) { _giftCodeRequestId = 0; done(updateGiftCode(slug, {})); }).send(); } GiftCode Premium::updateGiftCode( const QString &slug, const GiftCode &code) { auto &now = _giftCodes[slug]; if (now != code) { now = code; _giftCodeUpdated.fire_copy(slug); } return code; } rpl::producer Premium::giftCodeValue(const QString &slug) const { return _giftCodeUpdated.events_starting_with_copy( slug ) | rpl::filter(rpl::mappers::_1 == slug) | rpl::map([=] { const auto i = _giftCodes.find(slug); return (i != end(_giftCodes)) ? i->second : GiftCode(); }); } void Premium::applyGiftCode(const QString &slug, Fn done) { _api.request(MTPpayments_ApplyGiftCode( MTP_string(slug) )).done([=](const MTPUpdates &result) { _session->api().applyUpdates(result); done({}); }).fail([=](const MTP::Error &error) { done(error.type()); }).send(); } void Premium::resolveGiveawayInfo( not_null peer, MsgId messageId, Fn done) { Expects(done != nullptr); _giveawayInfoDone = std::move(done); if (_giveawayInfoRequestId) { if (_giveawayInfoPeer == peer && _giveawayInfoMessageId == messageId) { return; } _api.request(_giveawayInfoRequestId).cancel(); } _giveawayInfoPeer = peer; _giveawayInfoMessageId = messageId; _giveawayInfoRequestId = _api.request(MTPpayments_GetGiveawayInfo( _giveawayInfoPeer->input(), MTP_int(_giveawayInfoMessageId.bare) )).done([=](const MTPpayments_GiveawayInfo &result) { _giveawayInfoRequestId = 0; auto info = GiveawayInfo(); result.match([&](const MTPDpayments_giveawayInfo &data) { info.participating = data.is_participating(); info.state = data.is_preparing_results() ? GiveawayState::Preparing : GiveawayState::Running; info.adminChannelId = data.vadmin_disallowed_chat_id() ? ChannelId(*data.vadmin_disallowed_chat_id()) : ChannelId(); info.disallowedCountry = qs( data.vdisallowed_country().value_or_empty()); info.tooEarlyDate = data.vjoined_too_early_date().value_or_empty(); info.startDate = data.vstart_date().v; }, [&](const MTPDpayments_giveawayInfoResults &data) { info.state = data.is_refunded() ? GiveawayState::Refunded : GiveawayState::Finished; info.giftCode = qs(data.vgift_code_slug().value_or_empty()); info.activatedCount = data.vactivated_count().value_or_empty(); info.finishDate = data.vfinish_date().v; info.startDate = data.vstart_date().v; info.credits = data.vstars_prize().value_or_empty(); }); _giveawayInfoDone(std::move(info)); }).fail([=] { _giveawayInfoRequestId = 0; _giveawayInfoDone({}); }).send(); } const Data::PremiumSubscriptionOptions &Premium::subscriptionOptions() const { return _subscriptionOptions; } rpl::producer<> Premium::someMessageMoneyRestrictionsResolved() const { return _someMessageMoneyRestrictionsResolved.events(); } void Premium::resolveMessageMoneyRestrictions(not_null user) { _resolveMessageMoneyRequiredUsers.emplace(user); if (!_messageMoneyRequestScheduled && _resolveMessageMoneyRequestedUsers.empty()) { _messageMoneyRequestScheduled = true; crl::on_main(_session, [=] { requestPremiumRequiredSlice(); }); } } void Premium::requestPremiumRequiredSlice() { _messageMoneyRequestScheduled = false; if (!_resolveMessageMoneyRequestedUsers.empty() || _resolveMessageMoneyRequiredUsers.empty()) { return; } constexpr auto kPerRequest = 100; auto users = MTP_vector_from_range(_resolveMessageMoneyRequiredUsers | ranges::views::transform(&UserData::inputUser)); if (users.v.size() > kPerRequest) { auto shortened = users.v; shortened.resize(kPerRequest); users = MTP_vector(std::move(shortened)); const auto from = begin(_resolveMessageMoneyRequiredUsers); _resolveMessageMoneyRequestedUsers = { from, from + kPerRequest }; _resolveMessageMoneyRequiredUsers.erase(from, from + kPerRequest); } else { _resolveMessageMoneyRequestedUsers = base::take(_resolveMessageMoneyRequiredUsers); } const auto finish = [=](const QVector &list) { auto index = 0; for (const auto &user : base::take(_resolveMessageMoneyRequestedUsers)) { const auto set = [&](bool requirePremium, int stars) { using Flag = UserDataFlag; constexpr auto me = Flag::RequiresPremiumToWrite; constexpr auto known = Flag::MessageMoneyRestrictionsKnown; constexpr auto hasPrem = Flag::HasRequirePremiumToWrite; constexpr auto hasStars = Flag::HasStarsPerMessage; user->setStarsPerMessage(stars); user->setFlags((user->flags() & ~me) | known | (requirePremium ? (me | hasPrem) : Flag()) | (stars ? hasStars : Flag())); }; if (index >= list.size()) { set(false, 0); continue; } list[index++].match([&](const MTPDrequirementToContactEmpty &) { set(false, 0); }, [&](const MTPDrequirementToContactPremium &) { set(true, 0); }, [&](const MTPDrequirementToContactPaidMessages &data) { set(false, data.vstars_amount().v); }); } if (!_messageMoneyRequestScheduled && !_resolveMessageMoneyRequiredUsers.empty()) { _messageMoneyRequestScheduled = true; crl::on_main(_session, [=] { requestPremiumRequiredSlice(); }); } _someMessageMoneyRestrictionsResolved.fire({}); }; _session->api().request( MTPusers_GetRequirementsToContact(std::move(users)) ).done([=](const MTPVector &result) { finish(result.v); }).fail([=] { finish({}); }).send(); } PremiumGiftCodeOptions::PremiumGiftCodeOptions(not_null peer) : _peer(peer) , _api(&peer->session().api().instance()) { } rpl::producer PremiumGiftCodeOptions::request() { return [=](auto consumer) { auto lifetime = rpl::lifetime(); using TLOption = MTPPremiumGiftCodeOption; _api.request(MTPpayments_GetPremiumGiftCodeOptions( MTP_flags(_peer->isChannel() ? MTPpayments_GetPremiumGiftCodeOptions::Flag::f_boost_peer : MTPpayments_GetPremiumGiftCodeOptions::Flag(0)), _peer->input() )).done([=](const MTPVector &result) { auto tlMapOptions = base::flat_map>(); for (const auto &tlOption : result.v) { const auto &data = tlOption.data(); tlMapOptions[data.vusers().v].push_back(tlOption); if (qs(data.vcurrency()) == Ui::kCreditsCurrency) { continue; } const auto token = Token{ data.vusers().v, data.vmonths().v }; _stores[token] = Store{ .amount = data.vamount().v, .currency = qs(data.vcurrency()), .product = qs(data.vstore_product().value_or_empty()), .quantity = data.vstore_quantity().value_or_empty(), }; if (!ranges::contains(_availablePresets, data.vusers().v)) { _availablePresets.push_back(data.vusers().v); } } for (const auto &[amount, tlOptions] : tlMapOptions) { if (amount == 1 && _optionsForOnePerson.currencies.empty()) { for (const auto &option : tlOptions) { _optionsForOnePerson.months.push_back( option.data().vmonths().v); _optionsForOnePerson.totalCosts.push_back( option.data().vamount().v); _optionsForOnePerson.currencies.push_back( qs(option.data().vcurrency())); } } _subscriptionOptions[amount] = GiftCodesFromTL(tlOptions); } consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return lifetime; }; } rpl::producer PremiumGiftCodeOptions::applyPrepaid( const Payments::InvoicePremiumGiftCode &invoice, uint64 prepaidId) { return [=](auto consumer) { auto lifetime = rpl::lifetime(); const auto channel = _peer->asChannel(); if (!channel) { return lifetime; } _api.request(MTPpayments_LaunchPrepaidGiveaway( _peer->input(), MTP_long(prepaidId), invoice.giveawayCredits ? Payments::InvoiceCreditsGiveawayToTL(invoice) : Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice) )).done([=](const MTPUpdates &result) { _peer->session().api().applyUpdates(result); consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return lifetime; }; } const std::vector &PremiumGiftCodeOptions::availablePresets() const { return _availablePresets; } [[nodiscard]] int PremiumGiftCodeOptions::monthsFromPreset(int monthsIndex) { Expects(monthsIndex >= 0 && monthsIndex < _availablePresets.size()); return _optionsForOnePerson.months[monthsIndex]; } Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice( int users, int months) { const auto randomId = base::RandomValue(); const auto token = Token{ users, months }; const auto &store = _stores[token]; return Payments::InvoicePremiumGiftCode{ .currency = store.currency, .storeProduct = store.product, .randomId = randomId, .amount = store.amount, .storeQuantity = store.quantity, .users = token.users, .months = token.months, }; } std::vector PremiumGiftCodeOptions::optionsForPeer() const { auto result = std::vector(); if (!_optionsForOnePerson.currencies.empty()) { const auto count = int(_optionsForOnePerson.months.size()); result.reserve(count); for (auto i = 0; i != count; ++i) { Assert(i < _optionsForOnePerson.totalCosts.size()); Assert(i < _optionsForOnePerson.currencies.size()); result.push_back({ .cost = _optionsForOnePerson.totalCosts[i], .currency = _optionsForOnePerson.currencies[i], .months = _optionsForOnePerson.months[i], }); } } return result; } Data::PremiumSubscriptionOptions PremiumGiftCodeOptions::optionsForGiveaway( int usersCount) { const auto skipForStars = [&](Data::PremiumSubscriptionOptions options) { const auto proj = &Data::PremiumSubscriptionOption::currency; options.erase( ranges::remove(options, Ui::kCreditsCurrency, proj), end(options)); return options; }; const auto it = _subscriptionOptions.find(usersCount); if (it != end(_subscriptionOptions)) { return skipForStars(it->second); } else { auto tlOptions = QVector(); for (auto i = 0; i < _optionsForOnePerson.months.size(); i++) { tlOptions.push_back(MTP_premiumGiftCodeOption( MTP_flags(MTPDpremiumGiftCodeOption::Flags(0)), MTP_int(usersCount), MTP_int(_optionsForOnePerson.months[i]), MTPstring(), MTPint(), MTP_string(_optionsForOnePerson.currencies[i]), MTP_long(_optionsForOnePerson.totalCosts[i] * usersCount))); } _subscriptionOptions[usersCount] = GiftCodesFromTL(tlOptions); return skipForStars(_subscriptionOptions[usersCount]); } } auto PremiumGiftCodeOptions::requestStarGifts() -> rpl::producer { return [=](auto consumer) { auto lifetime = rpl::lifetime(); _api.request(MTPpayments_GetStarGifts( MTP_int(0) )).done([=](const MTPpayments_StarGifts &result) { result.match([&](const MTPDpayments_starGifts &data) { _peer->owner().processUsers(data.vusers()); _peer->owner().processChats(data.vchats()); _giftsHash = data.vhash().v; const auto &list = data.vgifts().v; const auto session = &_peer->session(); auto gifts = std::vector(); gifts.reserve(list.size()); for (const auto &gift : list) { if (auto parsed = FromTL(session, gift)) { gifts.push_back(std::move(*parsed)); } } _gifts = std::move(gifts); }, [&](const MTPDpayments_starGiftsNotModified &) { }); consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return lifetime; }; } auto PremiumGiftCodeOptions::starGifts() const -> const std::vector & { return _gifts; } int PremiumGiftCodeOptions::giveawayBoostsPerPremium() const { constexpr auto kFallbackCount = 4; return _peer->session().appConfig().get( u"giveaway_boosts_per_premium"_q, kFallbackCount); } int PremiumGiftCodeOptions::giveawayCountriesMax() const { constexpr auto kFallbackCount = 10; return _peer->session().appConfig().get( u"giveaway_countries_max"_q, kFallbackCount); } int PremiumGiftCodeOptions::giveawayAddPeersMax() const { constexpr auto kFallbackCount = 10; return _peer->session().appConfig().get( u"giveaway_add_peers_max"_q, kFallbackCount); } int PremiumGiftCodeOptions::giveawayPeriodMax() const { constexpr auto kFallbackCount = 3600 * 24 * 7; return _peer->session().appConfig().get( u"giveaway_period_max"_q, kFallbackCount); } bool PremiumGiftCodeOptions::giveawayGiftsPurchaseAvailable() const { return _peer->session().appConfig().get( u"giveaway_gifts_purchase_available"_q, false); } SponsoredToggle::SponsoredToggle(not_null session) : _api(&session->api().instance()) { } rpl::producer SponsoredToggle::toggled() { return [=](auto consumer) { auto lifetime = rpl::lifetime(); _api.request(MTPusers_GetFullUser( MTP_inputUserSelf() )).done([=](const MTPusers_UserFull &result) { consumer.put_next_copy( result.data().vfull_user().data().is_sponsored_enabled()); }).fail([=] { consumer.put_next(false); }).send(); return lifetime; }; } rpl::producer SponsoredToggle::setToggled(bool v) { return [=](auto consumer) { auto lifetime = rpl::lifetime(); _api.request(MTPaccount_ToggleSponsoredMessages( MTP_bool(v) )).done([=] { consumer.put_done(); }).fail([=](const MTP::Error &error) { consumer.put_error_copy(error.type()); }).send(); return lifetime; }; } MessageMoneyRestriction ResolveMessageMoneyRestrictions( not_null peer, History *maybeHistory) { if (const auto channel = peer->asChannel()) { return { .starsPerMessage = channel->starsPerMessageChecked(), .known = true, }; } const auto user = peer->asUser(); if (!user) { return { .known = true }; } else if (user->messageMoneyRestrictionsKnown()) { return { .starsPerMessage = user->starsPerMessageChecked(), .premiumRequired = (user->requiresPremiumToWrite() && !user->session().premium()), .known = true, }; } else if (user->hasStarsPerMessage()) { return {}; } else if (!user->hasRequirePremiumToWrite()) { return { .known = true }; } else if (user->flags() & UserDataFlag::MutualContact) { return { .known = true }; } else if (!maybeHistory) { return {}; } const auto update = [&](bool require) { using Flag = UserDataFlag; constexpr auto known = Flag::MessageMoneyRestrictionsKnown; constexpr auto me = Flag::RequiresPremiumToWrite; user->setFlags((user->flags() & ~me) | known | (require ? me : Flag())); }; // We allow this potentially-heavy loop because in case we've opened // the chat and have a lot of messages `requires_premium` will be known. for (const auto &block : maybeHistory->blocks) { for (const auto &view : block->messages) { const auto item = view->data(); if (!item->out() && !item->isService()) { update(false); return { .known = true }; } } } if (user->isContact() // Here we know, that we're not in his contacts. && maybeHistory->loadedAtTop() // And no incoming messages. && maybeHistory->loadedAtBottom()) { return { .premiumRequired = !user->session().premium(), .known = true, }; } return {}; } rpl::producer RandomHelloStickerValue( not_null session) { const auto premium = &session->api().premium(); const auto random = [=] { const auto &v = premium->helloStickers(); Assert(!v.empty()); return v[base::RandomIndex(v.size())].get(); }; const auto &v = premium->helloStickers(); if (!v.empty()) { return rpl::single(random()); } return rpl::single( nullptr ) | rpl::then(premium->helloStickersUpdated( ) | rpl::filter([=] { return !premium->helloStickers().empty(); }) | rpl::take(1) | rpl::map(random)); } std::optional FromTL( not_null session, const MTPstarGift &gift) { return gift.match([&](const MTPDstarGift &data) { const auto document = session->data().processDocument( data.vsticker()); const auto resellPrice = data.vresell_min_stars().value_or_empty(); const auto remaining = data.vavailability_remains(); const auto total = data.vavailability_total(); if (!document->sticker()) { return std::optional(); } const auto releasedById = data.vreleased_by() ? peerFromMTP(*data.vreleased_by()) : PeerId(); const auto releasedBy = releasedById ? session->data().peer(releasedById).get() : nullptr; const auto background = [&] { if (!data.vbackground()) { return std::shared_ptr(); } const auto &fields = data.vbackground()->data(); using namespace Ui; return std::make_shared( Data::StarGiftBackground{ .center = ColorFromSerialized(fields.vcenter_color()), .edge = ColorFromSerialized(fields.vedge_color()), .text = ColorFromSerialized(fields.vtext_color()), }); }; return std::optional(Data::StarGift{ .id = uint64(data.vid().v), .background = background(), .stars = int64(data.vstars().v), .starsConverted = int64(data.vconvert_stars().v), .starsToUpgrade = int64(data.vupgrade_stars().value_or_empty()), .starsResellMin = int64(resellPrice), .document = document, .releasedBy = releasedBy, .resellTitle = qs(data.vtitle().value_or_empty()), .resellCount = int(data.vavailability_resale().value_or_empty()), .auctionSlug = qs(data.vauction_slug().value_or_empty()), .auctionGiftsPerRound = data.vgifts_per_round().value_or_empty(), .auctionStartDate = data.vauction_start_date().value_or_empty(), .limitedLeft = remaining.value_or_empty(), .limitedCount = total.value_or_empty(), .perUserTotal = data.vper_user_total().value_or_empty(), .perUserRemains = data.vper_user_remains().value_or_empty(), .upgradeVariants = data.vupgrade_variants().value_or_empty(), .firstSaleDate = data.vfirst_sale_date().value_or_empty(), .lastSaleDate = data.vlast_sale_date().value_or_empty(), .lockedUntilDate = data.vlocked_until_date().value_or_empty(), .requirePremium = data.is_require_premium(), .peerColorAvailable = data.is_peer_color_available(), .upgradable = data.vupgrade_stars().has_value(), .birthday = data.is_birthday(), .soldOut = data.is_sold_out(), }); }, [&](const MTPDstarGiftUnique &data) { const auto total = data.vavailability_total().v; auto model = std::optional(); auto pattern = std::optional(); for (const auto &attribute : data.vattributes().v) { attribute.match([&](const MTPDstarGiftAttributeModel &data) { model = FromTL(session, data); }, [&](const MTPDstarGiftAttributePattern &data) { pattern = FromTL(session, data); }, [&](const MTPDstarGiftAttributeBackdrop &data) { }, [&](const MTPDstarGiftAttributeOriginalDetails &data) { }); } if (!model || !model->document->sticker() || !pattern || !pattern->document->sticker()) { return std::optional(); } const auto releasedById = data.vreleased_by() ? peerFromMTP(*data.vreleased_by()) : PeerId(); const auto themeUserId = data.vtheme_peer() ? peerFromMTP(*data.vtheme_peer()) : PeerId(); const auto releasedBy = releasedById ? session->data().peer(releasedById).get() : nullptr; const auto themeUser = themeUserId ? session->data().peer(themeUserId).get() : nullptr; const auto colorCollectible = (data.vpeer_color() && data.vpeer_color()->type() == mtpc_peerColorCollectible) ? std::make_shared( Data::ParseColorCollectible( data.vpeer_color()->c_peerColorCollectible())) : nullptr; auto result = Data::StarGift{ .id = data.vid().v, .unique = std::make_shared(Data::UniqueGift{ .id = data.vid().v, .initialGiftId = data.vgift_id().v, .slug = qs(data.vslug()), .title = qs(data.vtitle()), .giftAddress = qs(data.vgift_address().value_or_empty()), .ownerAddress = qs(data.vowner_address().value_or_empty()), .ownerName = qs(data.vowner_name().value_or_empty()), .ownerId = (data.vowner_id() ? peerFromMTP(*data.vowner_id()) : PeerId()), .hostId = (data.vhost_id() ? peerFromMTP(*data.vhost_id()) : PeerId()), .releasedBy = releasedBy, .themeUser = themeUser, .nanoTonForResale = FindTonForResale(data.vresell_amount()), .craftChancePermille = data.vcraft_chance_permille().value_or_empty(), .starsForResale = FindStarsForResale(data.vresell_amount()), .starsMinOffer = data.voffer_min_stars().value_or(-1), .number = data.vnum().v, .onlyAcceptTon = data.is_resale_ton_only(), .canBeTheme = data.is_theme_available(), .crafted = data.is_crafted(), .burned = data.is_burned(), .model = *model, .pattern = *pattern, .value = (data.vvalue_amount() ? std::make_shared( Data::UniqueGiftValue{ .currency = qs( data.vvalue_currency().value_or_empty()), .valuePrice = int64( data.vvalue_amount().value_or_empty()), .valuePriceUsd = int64( data.vvalue_usd_amount().value_or_empty()), }) : nullptr), .peerColor = colorCollectible, }), .document = model->document, .releasedBy = releasedBy, .limitedLeft = (total - data.vavailability_issued().v), .limitedCount = total, .resellTonOnly = data.is_resale_ton_only(), .requirePremium = data.is_require_premium(), }; const auto unique = result.unique.get(); for (const auto &attribute : data.vattributes().v) { attribute.match([&](const MTPDstarGiftAttributeModel &data) { }, [&](const MTPDstarGiftAttributePattern &data) { }, [&](const MTPDstarGiftAttributeBackdrop &data) { unique->backdrop = FromTL(data); }, [&](const MTPDstarGiftAttributeOriginalDetails &data) { unique->originalDetails = FromTL(session, data); }); } return std::make_optional(std::move(result)); }); } std::optional FromTL( not_null to, const MTPsavedStarGift &gift) { const auto session = &to->session(); const auto &data = gift.data(); auto parsed = FromTL(session, data.vgift()); if (!parsed) { return {}; } else if (const auto unique = parsed->unique.get()) { unique->starsForTransfer = data.vtransfer_stars().value_or(-1); unique->exportAt = data.vcan_export_at().value_or_empty(); unique->canTransferAt = data.vcan_transfer_at().value_or_empty(); unique->canResellAt = data.vcan_resell_at().value_or_empty(); unique->canCraftAt = data.vcan_craft_at().value_or_empty(); } using Id = Data::SavedStarGiftId; const auto hasUnique = parsed->unique != nullptr; return Data::SavedStarGift{ .info = std::move(*parsed), .manageId = (to->isUser() ? Id::User(data.vmsg_id().value_or_empty()) : Id::Chat(to, data.vsaved_id().value_or_empty())), .collectionIds = (data.vcollection_id() ? (data.vcollection_id()->v | ranges::views::transform(&MTPint::v) | ranges::to_vector) : std::vector()), .message = (data.vmessage() ? Api::ParseTextWithEntities( session, *data.vmessage()) : TextWithEntities()), .starsConverted = int64(data.vconvert_stars().value_or_empty()), .starsUpgradedBySender = int64( data.vupgrade_stars().value_or_empty()), .starsForDetailsRemove = int64( data.vdrop_original_details_stars().value_or_empty()), .giftPrepayUpgradeHash = qs( data.vprepaid_upgrade_hash().value_or_empty()), .fromId = (data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId()), .date = data.vdate().v, .giftNum = data.vgift_num().value_or_empty(), .upgradeSeparate = data.is_upgrade_separate(), .upgradable = data.is_can_upgrade(), .anonymous = data.is_name_hidden(), .pinned = data.is_pinned_to_top() && hasUnique, .hidden = data.is_unsaved(), .mine = to->isSelf(), }; } int ParseRarity(const MTPStarGiftAttributeRarity &rarity) { return rarity.match([&](const MTPDstarGiftAttributeRarity &data) { return std::max(data.vpermille().v, 0); }, [&](const MTPDstarGiftAttributeRarityUncommon &) { return int(Data::UniqueGiftRarity::Uncommon); }, [&](const MTPDstarGiftAttributeRarityRare &) { return int(Data::UniqueGiftRarity::Rare); }, [&](const MTPDstarGiftAttributeRarityEpic &) { return int(Data::UniqueGiftRarity::Epic); }, [&](const MTPDstarGiftAttributeRarityLegendary &) { return int(Data::UniqueGiftRarity::Legendary); }); } Data::UniqueGiftModel FromTL( not_null session, const MTPDstarGiftAttributeModel &data) { auto result = Data::UniqueGiftModel{ .document = session->data().processDocument(data.vdocument()), }; result.name = qs(data.vname()); result.rarityValue = ParseRarity(data.vrarity()); return result; } Data::UniqueGiftPattern FromTL( not_null session, const MTPDstarGiftAttributePattern &data) { auto result = Data::UniqueGiftPattern{ .document = session->data().processDocument(data.vdocument()), }; result.document->overrideEmojiUsesTextColor(true); result.name = qs(data.vname()); result.rarityValue = ParseRarity(data.vrarity()); return result; } Data::UniqueGiftBackdrop FromTL(const MTPDstarGiftAttributeBackdrop &data) { auto result = Data::UniqueGiftBackdrop{ .id = data.vbackdrop_id().v }; result.name = qs(data.vname()); result.rarityValue = ParseRarity(data.vrarity()); result.centerColor = Ui::ColorFromSerialized( data.vcenter_color()); result.edgeColor = Ui::ColorFromSerialized( data.vedge_color()); result.patternColor = Ui::ColorFromSerialized( data.vpattern_color()); result.textColor = Ui::ColorFromSerialized( data.vtext_color()); return result; } Data::UniqueGiftOriginalDetails FromTL( not_null session, const MTPDstarGiftAttributeOriginalDetails &data) { auto result = Data::UniqueGiftOriginalDetails(); result.date = data.vdate().v; result.senderId = data.vsender_id() ? peerFromMTP(*data.vsender_id()) : PeerId(); result.recipientId = peerFromMTP(data.vrecipient_id()); result.message = data.vmessage() ? ParseTextWithEntities(session, *data.vmessage()) : TextWithEntities(); return result; } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_premium.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "data/data_premium_subscription_option.h" #include "data/data_star_gift.h" #include "mtproto/sender.h" class History; class ApiWrap; namespace Main { class Session; } // namespace Main namespace Payments { struct InvoicePremiumGiftCode; } // namespace Payments namespace Api { struct GiftCode { PeerId from = 0; PeerId to = 0; MsgId giveawayId = 0; TimeId date = 0; TimeId used = 0; // 0 if not used. int days = 0; bool giveaway = false; explicit operator bool() const { return days != 0; } friend inline bool operator==( const GiftCode&, const GiftCode&) = default; }; enum class GiveawayState { Invalid, Running, Preparing, Finished, Refunded, }; struct GiveawayInfo { QString giftCode; QString disallowedCountry; ChannelId adminChannelId = 0; GiveawayState state = GiveawayState::Invalid; TimeId tooEarlyDate = 0; TimeId finishDate = 0; TimeId startDate = 0; uint64 credits = 0; int winnersCount = 0; int activatedCount = 0; bool participating = false; explicit operator bool() const { return state != GiveawayState::Invalid; } }; struct GiftOptionData { int64 cost = 0; QString currency; int months = 0; }; class Premium final { public: explicit Premium(not_null api); void reload(); [[nodiscard]] rpl::producer statusTextValue() const; [[nodiscard]] auto videos() const -> const base::flat_map> &; [[nodiscard]] rpl::producer<> videosUpdated() const; [[nodiscard]] auto stickers() const -> const std::vector> &; [[nodiscard]] rpl::producer<> stickersUpdated() const; [[nodiscard]] auto cloudSet() const -> const std::vector> &; [[nodiscard]] rpl::producer<> cloudSetUpdated() const; [[nodiscard]] auto helloStickers() const -> const std::vector> &; [[nodiscard]] rpl::producer<> helloStickersUpdated() const; [[nodiscard]] int64 monthlyAmount() const; [[nodiscard]] QString monthlyCurrency() const; void checkGiftCode( const QString &slug, Fn done); GiftCode updateGiftCode(const QString &slug, const GiftCode &code); [[nodiscard]] rpl::producer giftCodeValue( const QString &slug) const; void applyGiftCode(const QString &slug, Fn done); void resolveGiveawayInfo( not_null peer, MsgId messageId, Fn done); [[nodiscard]] auto subscriptionOptions() const -> const Data::PremiumSubscriptionOptions &; [[nodiscard]] auto someMessageMoneyRestrictionsResolved() const -> rpl::producer<>; void resolveMessageMoneyRestrictions(not_null user); private: void reloadPromo(); void reloadStickers(); void reloadCloudSet(); void reloadHelloStickers(); void requestPremiumRequiredSlice(); const not_null _session; MTP::Sender _api; mtpRequestId _promoRequestId = 0; std::optional _statusText; rpl::event_stream _statusTextUpdates; base::flat_map> _videos; rpl::event_stream<> _videosUpdated; mtpRequestId _stickersRequestId = 0; uint64 _stickersHash = 0; std::vector> _stickers; rpl::event_stream<> _stickersUpdated; mtpRequestId _cloudSetRequestId = 0; uint64 _cloudSetHash = 0; std::vector> _cloudSet; rpl::event_stream<> _cloudSetUpdated; mtpRequestId _helloStickersRequestId = 0; uint64 _helloStickersHash = 0; std::vector> _helloStickers; rpl::event_stream<> _helloStickersUpdated; int64 _monthlyAmount = 0; QString _monthlyCurrency; mtpRequestId _giftCodeRequestId = 0; QString _giftCodeSlug; base::flat_map _giftCodes; rpl::event_stream _giftCodeUpdated; mtpRequestId _giveawayInfoRequestId = 0; PeerData *_giveawayInfoPeer = nullptr; MsgId _giveawayInfoMessageId = 0; Fn _giveawayInfoDone; Data::PremiumSubscriptionOptions _subscriptionOptions; rpl::event_stream<> _someMessageMoneyRestrictionsResolved; base::flat_set> _resolveMessageMoneyRequiredUsers; base::flat_set> _resolveMessageMoneyRequestedUsers; bool _messageMoneyRequestScheduled = false; }; class PremiumGiftCodeOptions final { public: PremiumGiftCodeOptions(not_null peer); [[nodiscard]] rpl::producer request(); [[nodiscard]] std::vector optionsForPeer() const; [[nodiscard]] Data::PremiumSubscriptionOptions optionsForGiveaway( int usersCount); [[nodiscard]] const std::vector &availablePresets() const; [[nodiscard]] int monthsFromPreset(int monthsIndex); [[nodiscard]] Payments::InvoicePremiumGiftCode invoice( int users, int months); [[nodiscard]] rpl::producer applyPrepaid( const Payments::InvoicePremiumGiftCode &invoice, uint64 prepaidId); [[nodiscard]] int giveawayBoostsPerPremium() const; [[nodiscard]] int giveawayCountriesMax() const; [[nodiscard]] int giveawayAddPeersMax() const; [[nodiscard]] int giveawayPeriodMax() const; [[nodiscard]] bool giveawayGiftsPurchaseAvailable() const; [[nodiscard]] rpl::producer requestStarGifts(); [[nodiscard]] const std::vector &starGifts() const; private: struct Token final { int users = 0; int months = 0; friend inline constexpr auto operator<=>(Token, Token) = default; }; struct Store final { uint64 amount = 0; QString currency; QString product; int quantity = 0; }; using Amount = int; using PremiumSubscriptionOptions = Data::PremiumSubscriptionOptions; const not_null _peer; base::flat_map _subscriptionOptions; struct { std::vector months; std::vector totalCosts; std::vector currencies; } _optionsForOnePerson; std::vector _availablePresets; base::flat_map _stores; int32 _giftsHash = 0; std::vector _gifts; MTP::Sender _api; }; class SponsoredToggle final { public: explicit SponsoredToggle(not_null session); [[nodiscard]] rpl::producer toggled(); [[nodiscard]] rpl::producer setToggled(bool); private: MTP::Sender _api; }; struct MessageMoneyRestriction { int starsPerMessage = 0; bool premiumRequired = false; bool known = false; explicit operator bool() const { return starsPerMessage != 0 || premiumRequired; } friend inline bool operator==( const MessageMoneyRestriction &, const MessageMoneyRestriction &) = default; }; [[nodiscard]] MessageMoneyRestriction ResolveMessageMoneyRestrictions( not_null peer, History *maybeHistory); [[nodiscard]] rpl::producer RandomHelloStickerValue( not_null session); [[nodiscard]] std::optional FromTL( not_null session, const MTPstarGift &gift); [[nodiscard]] std::optional FromTL( not_null to, const MTPsavedStarGift &gift); [[nodiscard]] Data::UniqueGiftModel FromTL( not_null session, const MTPDstarGiftAttributeModel &data); [[nodiscard]] Data::UniqueGiftPattern FromTL( not_null session, const MTPDstarGiftAttributePattern &data); [[nodiscard]] Data::UniqueGiftBackdrop FromTL( const MTPDstarGiftAttributeBackdrop &data); [[nodiscard]] Data::UniqueGiftOriginalDetails FromTL( not_null session, const MTPDstarGiftAttributeOriginalDetails &data); } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_premium_option.cpp ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_premium_option.h" #include "ui/text/format_values.h" namespace Api { constexpr auto kDiscountDivider = 1.; Data::PremiumSubscriptionOption CreateSubscriptionOption( int months, float64 monthlyAmount, int64 amount, const QString ¤cy, const QString &botUrl) { const auto baselineAmount = monthlyAmount * months; const auto discount = [&] { const auto percent = 1. - float64(amount) / baselineAmount; return base::SafeRound(percent * 100. / kDiscountDivider) * kDiscountDivider; }(); const auto hasDiscount = (discount > 0); return { .months = months, .duration = Ui::FormatTTL(months * 86400 * 31), .discount = hasDiscount ? QString::fromUtf8("\xe2\x88\x92%1%").arg(discount) : QString(), .costPerMonth = Ui::FillAmountAndCurrency( int64(base::SafeRound(amount / float64(months))), currency), .costNoDiscount = hasDiscount ? Ui::FillAmountAndCurrency( int64(base::SafeRound(baselineAmount)), currency) : QString(), .costPerYear = Ui::FillAmountAndCurrency( int64(base::SafeRound(amount / float64(months / 12.))), currency), .botUrl = botUrl, }; } } // namespace Api ================================================ FILE: Telegram/SourceFiles/api/api_premium_option.h ================================================ /* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "data/data_premium_subscription_option.h" namespace Api { [[nodiscard]] Data::PremiumSubscriptionOption CreateSubscriptionOption( int months, float64 monthlyAmount, int64 amount, const QString ¤cy, const QString &botUrl); template [[nodiscard]] auto PremiumSubscriptionOptionsFromTL( const QVector