diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fac166..6646223 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,19 +25,23 @@ generate_styles(lib_ui ${src_loc} "${style_files}" ui/colors.palette) generate_emoji(lib_ui emoji.txt emoji_suggestions/emoji_autocomplete.json) set_target_properties(lib_ui PROPERTIES AUTOMOC ON) -target_prepare_qrc(lib_ui) -target_precompile_headers(lib_ui PRIVATE ${src_loc}/ui/ui_pch.h) +target_precompile_headers(lib_ui PRIVATE $<$:${src_loc}/ui/ui_pch.h>) nice_target_sources(lib_ui ${src_loc} PRIVATE ${style_files} ui/colors.palette emoji_suggestions/emoji_autocomplete.json + fonts/fonts.qrc qt_conf/win.qrc + ui/dpr/dpr_icon.cpp + ui/dpr/dpr_icon.h + ui/dpr/dpr_image.h ui/effects/animation_value.cpp ui/effects/animation_value.h + ui/effects/animation_value_f.h ui/effects/animations.cpp ui/effects/animations.h ui/effects/cross_animation.cpp @@ -46,6 +50,9 @@ PRIVATE ui/effects/cross_line.h ui/effects/fade_animation.cpp ui/effects/fade_animation.h + ui/effects/frame_generator.cpp + ui/effects/frame_generator.h + ui/effects/gradient.cpp ui/effects/gradient.h ui/effects/numbers_animation.cpp ui/effects/numbers_animation.h @@ -57,8 +64,14 @@ PRIVATE ui/effects/radial_animation.h ui/effects/ripple_animation.cpp ui/effects/ripple_animation.h + ui/effects/round_area_with_shadow.cpp + ui/effects/round_area_with_shadow.h + ui/effects/show_animation.cpp + ui/effects/show_animation.h ui/effects/slide_animation.cpp ui/effects/slide_animation.h + ui/effects/spoiler_mess.cpp + ui/effects/spoiler_mess.h ui/gl/gl_detection.cpp ui/gl/gl_detection.h ui/gl/gl_image.cpp @@ -85,6 +98,8 @@ PRIVATE ui/layers/layer_manager.h ui/layers/layer_widget.cpp ui/layers/layer_widget.h + ui/layers/show.cpp + ui/layers/show.h ui/paint/arcs.cpp ui/paint/arcs.h ui/paint/blob.cpp @@ -93,10 +108,10 @@ PRIVATE ui/paint/blobs.h ui/paint/blobs_linear.cpp ui/paint/blobs_linear.h - ui/platform/linux/ui_linux_wayland_integration.cpp - ui/platform/linux/ui_linux_wayland_integration.h ui/platform/linux/ui_window_linux.cpp ui/platform/linux/ui_window_linux.h + ui/platform/linux/ui_window_title_linux.cpp + ui/platform/linux/ui_window_title_linux.h ui/platform/linux/ui_utility_linux.cpp ui/platform/linux/ui_utility_linux.h ui/platform/mac/ui_window_mac.h @@ -111,13 +126,14 @@ PRIVATE ui/platform/win/ui_window_title_win.h ui/platform/win/ui_window_win.cpp ui/platform/win/ui_window_win.h + ui/platform/win/ui_windows_direct_manipulation.cpp + ui/platform/win/ui_windows_direct_manipulation.h ui/platform/win/ui_utility_win.cpp ui/platform/win/ui_utility_win.h ui/platform/ui_platform_window_title.cpp ui/platform/ui_platform_window_title.h ui/platform/ui_platform_window.cpp ui/platform/ui_platform_window.h - ui/platform/ui_platform_utility.cpp ui/platform/ui_platform_utility.h ui/style/style_core.cpp ui/style/style_core.h @@ -139,15 +155,27 @@ PRIVATE ui/style/style_core_types.h ui/style/style_palette_colorizer.cpp ui/style/style_palette_colorizer.h + ui/text/custom_emoji_instance.cpp + ui/text/custom_emoji_instance.h ui/text/text.cpp ui/text/text.h ui/text/text_block.cpp ui/text/text_block.h + ui/text/text_custom_emoji.cpp + ui/text/text_custom_emoji.h ui/text/text_entity.cpp ui/text/text_entity.h + ui/text/text_extended_data.cpp + ui/text/text_extended_data.h ui/text/text_isolated_emoji.h + ui/text/text_parser.cpp + ui/text/text_parser.h + ui/text/text_renderer.cpp + ui/text/text_renderer.h ui/text/text_utilities.cpp ui/text/text_utilities.h + ui/text/text_variant.cpp + ui/text/text_variant.h ui/toast/toast.cpp ui/toast/toast.h ui/toast/toast_manager.cpp @@ -164,28 +192,48 @@ PRIVATE ui/widgets/checkbox.h ui/widgets/dropdown_menu.cpp ui/widgets/dropdown_menu.h + ui/widgets/icon_button_with_text.cpp + ui/widgets/icon_button_with_text.h ui/widgets/inner_dropdown.cpp ui/widgets/inner_dropdown.h - ui/widgets/input_fields.cpp - ui/widgets/input_fields.h + ui/widgets/fields/input_field.cpp + ui/widgets/fields/input_field.h + ui/widgets/fields/masked_input_field.cpp + ui/widgets/fields/masked_input_field.h + ui/widgets/fields/number_input.cpp + ui/widgets/fields/number_input.h + ui/widgets/fields/password_input.cpp + ui/widgets/fields/password_input.h + ui/widgets/fields/time_part_input.cpp + ui/widgets/fields/time_part_input.h ui/widgets/labels.cpp ui/widgets/labels.h ui/widgets/menu/menu.cpp ui/widgets/menu/menu.h ui/widgets/menu/menu_action.cpp ui/widgets/menu/menu_action.h + ui/widgets/menu/menu_add_action_callback.cpp + ui/widgets/menu/menu_add_action_callback.h + ui/widgets/menu/menu_add_action_callback_factory.cpp + ui/widgets/menu/menu_add_action_callback_factory.h ui/widgets/menu/menu_common.cpp ui/widgets/menu/menu_common.h ui/widgets/menu/menu_item_base.cpp ui/widgets/menu/menu_item_base.h + ui/widgets/menu/menu_multiline_action.cpp + ui/widgets/menu/menu_multiline_action.h ui/widgets/menu/menu_separator.cpp ui/widgets/menu/menu_separator.h ui/widgets/menu/menu_toggle.cpp ui/widgets/menu/menu_toggle.h + ui/widgets/elastic_scroll.cpp + ui/widgets/elastic_scroll.h ui/widgets/popup_menu.cpp ui/widgets/popup_menu.h ui/widgets/rp_window.cpp ui/widgets/rp_window.h + ui/widgets/separate_panel.cpp + ui/widgets/separate_panel.h ui/widgets/scroll_area.cpp ui/widgets/scroll_area.h ui/widgets/side_bar_button.cpp @@ -198,10 +246,14 @@ PRIVATE ui/widgets/tooltip.h ui/wrap/fade_wrap.cpp ui/wrap/fade_wrap.h + ui/wrap/follow_slide_wrap.cpp + ui/wrap/follow_slide_wrap.h ui/wrap/padding_wrap.cpp ui/wrap/padding_wrap.h ui/wrap/slide_wrap.cpp ui/wrap/slide_wrap.h + ui/wrap/table_layout.cpp + ui/wrap/table_layout.h ui/wrap/vertical_layout.cpp ui/wrap/vertical_layout.h ui/wrap/vertical_layout_reorder.cpp @@ -209,12 +261,19 @@ PRIVATE ui/wrap/wrap.h ui/abstract_button.cpp ui/abstract_button.h + ui/animated_icon.cpp + ui/animated_icon.h ui/basic_click_handlers.cpp ui/basic_click_handlers.h + ui/cached_special_layer_shadow_corners.cpp + ui/cached_special_layer_shadow_corners.h ui/click_handler.cpp ui/click_handler.h ui/delayed_activation.cpp ui/delayed_activation.h + ui/dragging_scroll_manager.cpp + ui/dragging_scroll_manager.h + ui/dynamic_image.h ui/emoji_config.cpp ui/emoji_config.h ui/focus_persister.h @@ -227,11 +286,10 @@ PRIVATE ui/painter.h ui/ph.cpp ui/ph.h + ui/rect.h ui/rect_part.h ui/round_rect.cpp ui/round_rect.h - ui/spoiler_click_handler.cpp - ui/spoiler_click_handler.h ui/rp_widget.cpp ui/rp_widget.h ui/ui_utility.cpp @@ -244,23 +302,13 @@ PRIVATE emoji_suggestions/emoji_suggestions_helper.h ) -if (DESKTOP_APP_USE_PACKAGED) - nice_target_sources(lib_ui ${src_loc} PRIVATE ui/text/qtextitemint.cpp) +if (DESKTOP_APP_USE_PACKAGED_FONTS) + target_compile_definitions(lib_ui PRIVATE LIB_UI_USE_PACKAGED_FONTS) + remove_target_sources(lib_ui ${src_loc} fonts/fonts.qrc) endif() -if (NOT DESKTOP_APP_USE_PACKAGED_FONTS) - nice_target_sources(lib_ui ${src_loc} PRIVATE fonts/fonts.qrc) -endif() - -if (DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION) - remove_target_sources(Telegram ${src_loc} ui/platform/linux/ui_linux_wayland_integration.cpp) - nice_target_sources(Telegram ${src_loc} PRIVATE ui/platform/linux/ui_linux_wayland_integration_dummy.cpp) -elseif(LINUX) - target_link_libraries(lib_ui - PUBLIC - desktop-app::lib_waylandshells - desktop-app::external_kwayland - ) +if (WIN32) + nuget_add_winrt(lib_ui) endif() target_include_directories(lib_ui @@ -274,4 +322,9 @@ PUBLIC desktop-app::lib_base PRIVATE desktop-app::external_zlib + desktop-app::external_jpeg + desktop-app::external_lz4 + desktop-app::external_xxhash ) + +target_prepare_qrc(lib_ui) diff --git a/emoji.txt b/emoji.txt index 6fba402..6e2ff47 100644 --- a/emoji.txt +++ b/emoji.txt @@ -1,22 +1,28 @@ -"๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿ˜…","๐Ÿ˜‚","๐Ÿคฃ","๐Ÿฅฒ","โ˜บ๏ธ","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿ™‚","๐Ÿ™ƒ","๐Ÿ˜‰","๐Ÿ˜Œ","๐Ÿ˜","๐Ÿฅฐ","๐Ÿ˜˜","๐Ÿ˜—","๐Ÿ˜™","๐Ÿ˜š","๐Ÿ˜‹","๐Ÿ˜›","๐Ÿ˜","๐Ÿ˜œ","๐Ÿคช","๐Ÿคจ","๐Ÿง","๐Ÿค“","๐Ÿ˜Ž","๐Ÿฅธ","๐Ÿคฉ","๐Ÿฅณ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ˜ž","๐Ÿ˜”","๐Ÿ˜Ÿ","๐Ÿ˜•","๐Ÿ™","โ˜น๏ธ","๐Ÿ˜ฃ","๐Ÿ˜–","๐Ÿ˜ซ","๐Ÿ˜ฉ","๐Ÿฅบ","๐Ÿ˜ข","๐Ÿ˜ญ","๐Ÿ˜ค","๐Ÿ˜ ","๐Ÿ˜ก","๐Ÿคฌ","๐Ÿคฏ","๐Ÿ˜ณ","๐Ÿฅต","๐Ÿฅถ","๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿ˜ฑ","๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜“","๐Ÿค—","๐Ÿค”","๐Ÿคญ","๐Ÿคซ","๐Ÿคฅ","๐Ÿ˜ถ","๐Ÿ˜","๐Ÿ˜‘","๐Ÿ˜ฌ","๐Ÿ™„","๐Ÿ˜ฏ","๐Ÿ˜ฆ","๐Ÿ˜ง","๐Ÿ˜ฎ","๐Ÿ˜ฒ","๐Ÿฅฑ","๐Ÿ˜ด","๐Ÿคค","๐Ÿ˜ช","๐Ÿ˜ฎโ€๐Ÿ’จ","๐Ÿ˜ต","๐Ÿ˜ตโ€๐Ÿ’ซ","๐Ÿค","๐Ÿฅด","๐Ÿคข","๐Ÿคฎ","๐Ÿคง","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿค‘","๐Ÿค ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ‘น","๐Ÿ‘บ","๐Ÿคก","๐Ÿ’ฉ","๐Ÿ‘ป","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ‘ฝ","๐Ÿ‘พ","๐Ÿค–","๐ŸŽƒ","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น","๐Ÿ˜ป","๐Ÿ˜ผ","๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ", +"๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿฅน","๐Ÿ˜…","๐Ÿ˜‚","๐Ÿคฃ","๐Ÿฅฒ","โ˜บ๏ธ","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿ™‚","๐Ÿ™ƒ","๐Ÿ˜‰","๐Ÿ˜Œ","๐Ÿ˜","๐Ÿฅฐ","๐Ÿ˜˜","๐Ÿ˜—","๐Ÿ˜™","๐Ÿ˜š","๐Ÿ˜‹","๐Ÿ˜›","๐Ÿ˜","๐Ÿ˜œ","๐Ÿคช","๐Ÿคจ","๐Ÿง","๐Ÿค“","๐Ÿ˜Ž","๐Ÿฅธ","๐Ÿคฉ","๐Ÿฅณ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ˜ž","๐Ÿ˜”","๐Ÿ˜Ÿ","๐Ÿ˜•","๐Ÿ™","โ˜น๏ธ","๐Ÿ˜ฃ","๐Ÿ˜–","๐Ÿ˜ซ","๐Ÿ˜ฉ","๐Ÿฅบ","๐Ÿ˜ข","๐Ÿ˜ญ","๐Ÿ˜ค","๐Ÿ˜ ","๐Ÿ˜ก","๐Ÿคฌ","๐Ÿคฏ","๐Ÿ˜ณ","๐Ÿฅต","๐Ÿฅถ","๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿ˜ฑ","๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜“","๐Ÿค—","๐Ÿค”","๐Ÿซฃ","๐Ÿคญ","๐Ÿซข","๐Ÿซก","๐Ÿคซ","๐Ÿซ ","๐Ÿคฅ","๐Ÿ˜ถ","๐Ÿซฅ","๐Ÿ˜","๐Ÿซค","๐Ÿ˜‘","๐Ÿซจ","๐Ÿ˜ฌ","๐Ÿ™„","๐Ÿ˜ฏ","๐Ÿ˜ฆ","๐Ÿ˜ง","๐Ÿ˜ฎ","๐Ÿ˜ฒ","๐Ÿฅฑ","๐Ÿ˜ด","๐Ÿคค","๐Ÿ˜ช","๐Ÿ˜ฎโ€๐Ÿ’จ","๐Ÿ˜ต","๐Ÿ˜ตโ€๐Ÿ’ซ","๐Ÿค","๐Ÿฅด","๐Ÿคข","๐Ÿคฎ","๐Ÿคง","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿค‘","๐Ÿค ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ‘น","๐Ÿ‘บ","๐Ÿคก","๐Ÿ’ฉ","๐Ÿ‘ป","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ‘ฝ","๐Ÿ‘พ","๐Ÿค–","๐ŸŽƒ","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น","๐Ÿ˜ป","๐Ÿ˜ผ","๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ", +"๐Ÿซถ","๐Ÿซถ๐Ÿป","๐Ÿซถ๐Ÿผ","๐Ÿซถ๐Ÿฝ","๐Ÿซถ๐Ÿพ","๐Ÿซถ๐Ÿฟ", "๐Ÿคฒ","๐Ÿคฒ๐Ÿป","๐Ÿคฒ๐Ÿผ","๐Ÿคฒ๐Ÿฝ","๐Ÿคฒ๐Ÿพ","๐Ÿคฒ๐Ÿฟ", "๐Ÿ‘","๐Ÿ‘๐Ÿป","๐Ÿ‘๐Ÿผ","๐Ÿ‘๐Ÿฝ","๐Ÿ‘๐Ÿพ","๐Ÿ‘๐Ÿฟ", "๐Ÿ™Œ","๐Ÿ™Œ๐Ÿป","๐Ÿ™Œ๐Ÿผ","๐Ÿ™Œ๐Ÿฝ","๐Ÿ™Œ๐Ÿพ","๐Ÿ™Œ๐Ÿฟ", "๐Ÿ‘","๐Ÿ‘๐Ÿป","๐Ÿ‘๐Ÿผ","๐Ÿ‘๐Ÿฝ","๐Ÿ‘๐Ÿพ","๐Ÿ‘๐Ÿฟ", -"๐Ÿค", +"๐Ÿค","๐Ÿค๐Ÿป","๐Ÿซฑ๐Ÿปโ€๐Ÿซฒ๐Ÿผ","๐Ÿซฑ๐Ÿปโ€๐Ÿซฒ๐Ÿฝ","๐Ÿซฑ๐Ÿปโ€๐Ÿซฒ๐Ÿพ","๐Ÿซฑ๐Ÿปโ€๐Ÿซฒ๐Ÿฟ","๐Ÿซฑ๐Ÿผโ€๐Ÿซฒ๐Ÿป","๐Ÿค๐Ÿผ","๐Ÿซฑ๐Ÿผโ€๐Ÿซฒ๐Ÿฝ","๐Ÿซฑ๐Ÿผโ€๐Ÿซฒ๐Ÿพ","๐Ÿซฑ๐Ÿผโ€๐Ÿซฒ๐Ÿฟ","๐Ÿซฑ๐Ÿฝโ€๐Ÿซฒ๐Ÿป","๐Ÿซฑ๐Ÿฝโ€๐Ÿซฒ๐Ÿผ","๐Ÿค๐Ÿฝ","๐Ÿซฑ๐Ÿฝโ€๐Ÿซฒ๐Ÿพ","๐Ÿซฑ๐Ÿฝโ€๐Ÿซฒ๐Ÿฟ","๐Ÿซฑ๐Ÿพโ€๐Ÿซฒ๐Ÿป","๐Ÿซฑ๐Ÿพโ€๐Ÿซฒ๐Ÿผ","๐Ÿซฑ๐Ÿพโ€๐Ÿซฒ๐Ÿฝ","๐Ÿค๐Ÿพ","๐Ÿซฑ๐Ÿพโ€๐Ÿซฒ๐Ÿฟ","๐Ÿซฑ๐Ÿฟโ€๐Ÿซฒ๐Ÿป","๐Ÿซฑ๐Ÿฟโ€๐Ÿซฒ๐Ÿผ","๐Ÿซฑ๐Ÿฟโ€๐Ÿซฒ๐Ÿฝ","๐Ÿซฑ๐Ÿฟโ€๐Ÿซฒ๐Ÿพ","๐Ÿค๐Ÿฟ", "๐Ÿ‘","๐Ÿ‘๐Ÿป","๐Ÿ‘๐Ÿผ","๐Ÿ‘๐Ÿฝ","๐Ÿ‘๐Ÿพ","๐Ÿ‘๐Ÿฟ", "๐Ÿ‘Ž","๐Ÿ‘Ž๐Ÿป","๐Ÿ‘Ž๐Ÿผ","๐Ÿ‘Ž๐Ÿฝ","๐Ÿ‘Ž๐Ÿพ","๐Ÿ‘Ž๐Ÿฟ", "๐Ÿ‘Š","๐Ÿ‘Š๐Ÿป","๐Ÿ‘Š๐Ÿผ","๐Ÿ‘Š๐Ÿฝ","๐Ÿ‘Š๐Ÿพ","๐Ÿ‘Š๐Ÿฟ", "โœŠ","โœŠ๐Ÿป","โœŠ๐Ÿผ","โœŠ๐Ÿฝ","โœŠ๐Ÿพ","โœŠ๐Ÿฟ", "๐Ÿค›","๐Ÿค›๐Ÿป","๐Ÿค›๐Ÿผ","๐Ÿค›๐Ÿฝ","๐Ÿค›๐Ÿพ","๐Ÿค›๐Ÿฟ", "๐Ÿคœ","๐Ÿคœ๐Ÿป","๐Ÿคœ๐Ÿผ","๐Ÿคœ๐Ÿฝ","๐Ÿคœ๐Ÿพ","๐Ÿคœ๐Ÿฟ", +"๐Ÿซท","๐Ÿซท๐Ÿป","๐Ÿซท๐Ÿผ","๐Ÿซท๐Ÿฝ","๐Ÿซท๐Ÿพ","๐Ÿซท๐Ÿฟ", +"๐Ÿซธ","๐Ÿซธ๐Ÿป","๐Ÿซธ๐Ÿผ","๐Ÿซธ๐Ÿฝ","๐Ÿซธ๐Ÿพ","๐Ÿซธ๐Ÿฟ", "๐Ÿคž","๐Ÿคž๐Ÿป","๐Ÿคž๐Ÿผ","๐Ÿคž๐Ÿฝ","๐Ÿคž๐Ÿพ","๐Ÿคž๐Ÿฟ", "โœŒ๏ธ","โœŒ๐Ÿป","โœŒ๐Ÿผ","โœŒ๐Ÿฝ","โœŒ๐Ÿพ","โœŒ๐Ÿฟ", +"๐Ÿซฐ","๐Ÿซฐ๐Ÿป","๐Ÿซฐ๐Ÿผ","๐Ÿซฐ๐Ÿฝ","๐Ÿซฐ๐Ÿพ","๐Ÿซฐ๐Ÿฟ", "๐ŸคŸ","๐ŸคŸ๐Ÿป","๐ŸคŸ๐Ÿผ","๐ŸคŸ๐Ÿฝ","๐ŸคŸ๐Ÿพ","๐ŸคŸ๐Ÿฟ", "๐Ÿค˜","๐Ÿค˜๐Ÿป","๐Ÿค˜๐Ÿผ","๐Ÿค˜๐Ÿฝ","๐Ÿค˜๐Ÿพ","๐Ÿค˜๐Ÿฟ", "๐Ÿ‘Œ","๐Ÿ‘Œ๐Ÿป","๐Ÿ‘Œ๐Ÿผ","๐Ÿ‘Œ๐Ÿฝ","๐Ÿ‘Œ๐Ÿพ","๐Ÿ‘Œ๐Ÿฟ", "๐ŸคŒ","๐ŸคŒ๐Ÿป","๐ŸคŒ๐Ÿผ","๐ŸคŒ๐Ÿฝ","๐ŸคŒ๐Ÿพ","๐ŸคŒ๐Ÿฟ", "๐Ÿค","๐Ÿค๐Ÿป","๐Ÿค๐Ÿผ","๐Ÿค๐Ÿฝ","๐Ÿค๐Ÿพ","๐Ÿค๐Ÿฟ", +"๐Ÿซณ","๐Ÿซณ๐Ÿป","๐Ÿซณ๐Ÿผ","๐Ÿซณ๐Ÿฝ","๐Ÿซณ๐Ÿพ","๐Ÿซณ๐Ÿฟ", +"๐Ÿซด","๐Ÿซด๐Ÿป","๐Ÿซด๐Ÿผ","๐Ÿซด๐Ÿฝ","๐Ÿซด๐Ÿพ","๐Ÿซด๐Ÿฟ", "๐Ÿ‘ˆ","๐Ÿ‘ˆ๐Ÿป","๐Ÿ‘ˆ๐Ÿผ","๐Ÿ‘ˆ๐Ÿฝ","๐Ÿ‘ˆ๐Ÿพ","๐Ÿ‘ˆ๐Ÿฟ", "๐Ÿ‘‰","๐Ÿ‘‰๐Ÿป","๐Ÿ‘‰๐Ÿผ","๐Ÿ‘‰๐Ÿฝ","๐Ÿ‘‰๐Ÿพ","๐Ÿ‘‰๐Ÿฟ", "๐Ÿ‘†","๐Ÿ‘†๐Ÿป","๐Ÿ‘†๐Ÿผ","๐Ÿ‘†๐Ÿฝ","๐Ÿ‘†๐Ÿพ","๐Ÿ‘†๐Ÿฟ", @@ -28,14 +34,17 @@ "๐Ÿ––","๐Ÿ––๐Ÿป","๐Ÿ––๐Ÿผ","๐Ÿ––๐Ÿฝ","๐Ÿ––๐Ÿพ","๐Ÿ––๐Ÿฟ", "๐Ÿ‘‹","๐Ÿ‘‹๐Ÿป","๐Ÿ‘‹๐Ÿผ","๐Ÿ‘‹๐Ÿฝ","๐Ÿ‘‹๐Ÿพ","๐Ÿ‘‹๐Ÿฟ", "๐Ÿค™","๐Ÿค™๐Ÿป","๐Ÿค™๐Ÿผ","๐Ÿค™๐Ÿฝ","๐Ÿค™๐Ÿพ","๐Ÿค™๐Ÿฟ", +"๐Ÿซฒ","๐Ÿซฒ๐Ÿป","๐Ÿซฒ๐Ÿผ","๐Ÿซฒ๐Ÿฝ","๐Ÿซฒ๐Ÿพ","๐Ÿซฒ๐Ÿฟ", +"๐Ÿซฑ","๐Ÿซฑ๐Ÿป","๐Ÿซฑ๐Ÿผ","๐Ÿซฑ๐Ÿฝ","๐Ÿซฑ๐Ÿพ","๐Ÿซฑ๐Ÿฟ", "๐Ÿ’ช","๐Ÿ’ช๐Ÿป","๐Ÿ’ช๐Ÿผ","๐Ÿ’ช๐Ÿฝ","๐Ÿ’ช๐Ÿพ","๐Ÿ’ช๐Ÿฟ", "๐Ÿฆพ", "๐Ÿ–•","๐Ÿ–•๐Ÿป","๐Ÿ–•๐Ÿผ","๐Ÿ–•๐Ÿฝ","๐Ÿ–•๐Ÿพ","๐Ÿ–•๐Ÿฟ", "โœ๏ธ","โœ๐Ÿป","โœ๐Ÿผ","โœ๐Ÿฝ","โœ๐Ÿพ","โœ๐Ÿฟ", "๐Ÿ™","๐Ÿ™๐Ÿป","๐Ÿ™๐Ÿผ","๐Ÿ™๐Ÿฝ","๐Ÿ™๐Ÿพ","๐Ÿ™๐Ÿฟ", +"๐Ÿซต","๐Ÿซต๐Ÿป","๐Ÿซต๐Ÿผ","๐Ÿซต๐Ÿฝ","๐Ÿซต๐Ÿพ","๐Ÿซต๐Ÿฟ", "๐Ÿฆถ","๐Ÿฆถ๐Ÿป","๐Ÿฆถ๐Ÿผ","๐Ÿฆถ๐Ÿฝ","๐Ÿฆถ๐Ÿพ","๐Ÿฆถ๐Ÿฟ", "๐Ÿฆต","๐Ÿฆต๐Ÿป","๐Ÿฆต๐Ÿผ","๐Ÿฆต๐Ÿฝ","๐Ÿฆต๐Ÿพ","๐Ÿฆต๐Ÿฟ", -"๐Ÿฆฟ","๐Ÿ’„","๐Ÿ’‹","๐Ÿ‘„","๐Ÿฆท","๐Ÿ‘…", +"๐Ÿฆฟ","๐Ÿ’„","๐Ÿ’‹","๐Ÿ‘„","๐Ÿซฆ","๐Ÿฆท","๐Ÿ‘…", "๐Ÿ‘‚","๐Ÿ‘‚๐Ÿป","๐Ÿ‘‚๐Ÿผ","๐Ÿ‘‚๐Ÿฝ","๐Ÿ‘‚๐Ÿพ","๐Ÿ‘‚๐Ÿฟ", "๐Ÿฆป","๐Ÿฆป๐Ÿป","๐Ÿฆป๐Ÿผ","๐Ÿฆป๐Ÿฝ","๐Ÿฆป๐Ÿพ","๐Ÿฆป๐Ÿฟ", "๐Ÿ‘ƒ","๐Ÿ‘ƒ๐Ÿป","๐Ÿ‘ƒ๐Ÿผ","๐Ÿ‘ƒ๐Ÿฝ","๐Ÿ‘ƒ๐Ÿพ","๐Ÿ‘ƒ๐Ÿฟ", @@ -140,6 +149,7 @@ "๐Ÿคต","๐Ÿคต๐Ÿป","๐Ÿคต๐Ÿผ","๐Ÿคต๐Ÿฝ","๐Ÿคต๐Ÿพ","๐Ÿคต๐Ÿฟ", "๐Ÿคตโ€โ™‚๏ธ","๐Ÿคต๐Ÿปโ€โ™‚๏ธ","๐Ÿคต๐Ÿผโ€โ™‚๏ธ","๐Ÿคต๐Ÿฝโ€โ™‚๏ธ","๐Ÿคต๐Ÿพโ€โ™‚๏ธ","๐Ÿคต๐Ÿฟโ€โ™‚๏ธ", "๐Ÿ‘ธ","๐Ÿ‘ธ๐Ÿป","๐Ÿ‘ธ๐Ÿผ","๐Ÿ‘ธ๐Ÿฝ","๐Ÿ‘ธ๐Ÿพ","๐Ÿ‘ธ๐Ÿฟ", +"๐Ÿซ…","๐Ÿซ…๐Ÿป","๐Ÿซ…๐Ÿผ","๐Ÿซ…๐Ÿฝ","๐Ÿซ…๐Ÿพ","๐Ÿซ…๐Ÿฟ", "๐Ÿคด","๐Ÿคด๐Ÿป","๐Ÿคด๐Ÿผ","๐Ÿคด๐Ÿฝ","๐Ÿคด๐Ÿพ","๐Ÿคด๐Ÿฟ", "๐Ÿฅท","๐Ÿฅท๐Ÿป","๐Ÿฅท๐Ÿผ","๐Ÿฅท๐Ÿฝ","๐Ÿฅท๐Ÿพ","๐Ÿฅท๐Ÿฟ", "๐Ÿฆธโ€โ™€๏ธ","๐Ÿฆธ๐Ÿปโ€โ™€๏ธ","๐Ÿฆธ๐Ÿผโ€โ™€๏ธ","๐Ÿฆธ๐Ÿฝโ€โ™€๏ธ","๐Ÿฆธ๐Ÿพโ€โ™€๏ธ","๐Ÿฆธ๐Ÿฟโ€โ™€๏ธ", @@ -157,6 +167,7 @@ "๐Ÿงโ€โ™€๏ธ","๐Ÿง๐Ÿปโ€โ™€๏ธ","๐Ÿง๐Ÿผโ€โ™€๏ธ","๐Ÿง๐Ÿฝโ€โ™€๏ธ","๐Ÿง๐Ÿพโ€โ™€๏ธ","๐Ÿง๐Ÿฟโ€โ™€๏ธ", "๐Ÿง","๐Ÿง๐Ÿป","๐Ÿง๐Ÿผ","๐Ÿง๐Ÿฝ","๐Ÿง๐Ÿพ","๐Ÿง๐Ÿฟ", "๐Ÿงโ€โ™‚๏ธ","๐Ÿง๐Ÿปโ€โ™‚๏ธ","๐Ÿง๐Ÿผโ€โ™‚๏ธ","๐Ÿง๐Ÿฝโ€โ™‚๏ธ","๐Ÿง๐Ÿพโ€โ™‚๏ธ","๐Ÿง๐Ÿฟโ€โ™‚๏ธ", +"๐ŸงŒ", "๐Ÿง›โ€โ™€๏ธ","๐Ÿง›๐Ÿปโ€โ™€๏ธ","๐Ÿง›๐Ÿผโ€โ™€๏ธ","๐Ÿง›๐Ÿฝโ€โ™€๏ธ","๐Ÿง›๐Ÿพโ€โ™€๏ธ","๐Ÿง›๐Ÿฟโ€โ™€๏ธ", "๐Ÿง›","๐Ÿง›๐Ÿป","๐Ÿง›๐Ÿผ","๐Ÿง›๐Ÿฝ","๐Ÿง›๐Ÿพ","๐Ÿง›๐Ÿฟ", "๐Ÿง›โ€โ™‚๏ธ","๐Ÿง›๐Ÿปโ€โ™‚๏ธ","๐Ÿง›๐Ÿผโ€โ™‚๏ธ","๐Ÿง›๐Ÿฝโ€โ™‚๏ธ","๐Ÿง›๐Ÿพโ€โ™‚๏ธ","๐Ÿง›๐Ÿฟโ€โ™‚๏ธ", @@ -169,6 +180,8 @@ "๐Ÿงšโ€โ™‚๏ธ","๐Ÿงš๐Ÿปโ€โ™‚๏ธ","๐Ÿงš๐Ÿผโ€โ™‚๏ธ","๐Ÿงš๐Ÿฝโ€โ™‚๏ธ","๐Ÿงš๐Ÿพโ€โ™‚๏ธ","๐Ÿงš๐Ÿฟโ€โ™‚๏ธ", "๐Ÿ‘ผ","๐Ÿ‘ผ๐Ÿป","๐Ÿ‘ผ๐Ÿผ","๐Ÿ‘ผ๐Ÿฝ","๐Ÿ‘ผ๐Ÿพ","๐Ÿ‘ผ๐Ÿฟ", "๐Ÿคฐ","๐Ÿคฐ๐Ÿป","๐Ÿคฐ๐Ÿผ","๐Ÿคฐ๐Ÿฝ","๐Ÿคฐ๐Ÿพ","๐Ÿคฐ๐Ÿฟ", +"๐Ÿซ„","๐Ÿซ„๐Ÿป","๐Ÿซ„๐Ÿผ","๐Ÿซ„๐Ÿฝ","๐Ÿซ„๐Ÿพ","๐Ÿซ„๐Ÿฟ", +"๐Ÿซƒ","๐Ÿซƒ๐Ÿป","๐Ÿซƒ๐Ÿผ","๐Ÿซƒ๐Ÿฝ","๐Ÿซƒ๐Ÿพ","๐Ÿซƒ๐Ÿฟ", "๐Ÿคฑ","๐Ÿคฑ๐Ÿป","๐Ÿคฑ๐Ÿผ","๐Ÿคฑ๐Ÿฝ","๐Ÿคฑ๐Ÿพ","๐Ÿคฑ๐Ÿฟ", "๐Ÿ‘ฉโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿผ", "๐Ÿง‘โ€๐Ÿผ","๐Ÿง‘๐Ÿปโ€๐Ÿผ","๐Ÿง‘๐Ÿผโ€๐Ÿผ","๐Ÿง‘๐Ÿฝโ€๐Ÿผ","๐Ÿง‘๐Ÿพโ€๐Ÿผ","๐Ÿง‘๐Ÿฟโ€๐Ÿผ", @@ -253,13 +266,13 @@ "๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿชข","๐Ÿงถ","๐Ÿงต","๐Ÿชก","๐Ÿงฅ","๐Ÿฅผ","๐Ÿฆบ","๐Ÿ‘š","๐Ÿ‘•","๐Ÿ‘–","๐Ÿฉฒ","๐Ÿฉณ","๐Ÿ‘”","๐Ÿ‘—","๐Ÿ‘™","๐Ÿฉฑ","๐Ÿ‘˜","๐Ÿฅป","๐Ÿฉด","๐Ÿฅฟ","๐Ÿ‘ ","๐Ÿ‘ก","๐Ÿ‘ข","๐Ÿ‘ž","๐Ÿ‘Ÿ","๐Ÿฅพ","๐Ÿงฆ","๐Ÿงค","๐Ÿงฃ","๐ŸŽฉ","๐Ÿงข","๐Ÿ‘’","๐ŸŽ“","โ›‘","๐Ÿช–","๐Ÿ‘‘","๐Ÿ’","๐Ÿ‘","๐Ÿ‘›","๐Ÿ‘œ","๐Ÿ’ผ","๐ŸŽ’","๐Ÿงณ","๐Ÿ‘“","๐Ÿ•ถ","๐Ÿฅฝ","๐ŸŒ‚" -"๐Ÿถ","๐Ÿฑ","๐Ÿญ","๐Ÿน","๐Ÿฐ","๐ŸฆŠ","๐Ÿป","๐Ÿผ","๐Ÿปโ€โ„๏ธ","๐Ÿจ","๐Ÿฏ","๐Ÿฆ","๐Ÿฎ","๐Ÿท","๐Ÿฝ","๐Ÿธ","๐Ÿต","๐Ÿ™ˆ","๐Ÿ™‰","๐Ÿ™Š","๐Ÿ’","๐Ÿ”","๐Ÿง","๐Ÿฆ","๐Ÿค","๐Ÿฃ","๐Ÿฅ","๐Ÿฆ†","๐Ÿฆ…","๐Ÿฆ‰","๐Ÿฆ‡","๐Ÿบ","๐Ÿ—","๐Ÿด","๐Ÿฆ„","๐Ÿ","๐Ÿชฑ","๐Ÿ›","๐Ÿฆ‹","๐ŸŒ","๐Ÿž","๐Ÿœ","๐Ÿชฐ","๐Ÿชฒ","๐Ÿชณ","๐ŸฆŸ","๐Ÿฆ—","๐Ÿ•ท","๐Ÿ•ธ","๐Ÿฆ‚","๐Ÿข","๐Ÿ","๐ŸฆŽ","๐Ÿฆ–","๐Ÿฆ•","๐Ÿ™","๐Ÿฆ‘","๐Ÿฆ","๐Ÿฆž","๐Ÿฆ€","๐Ÿก","๐Ÿ ","๐ŸŸ","๐Ÿฌ","๐Ÿณ","๐Ÿ‹","๐Ÿฆˆ","๐Ÿฆญ","๐ŸŠ","๐Ÿ…","๐Ÿ†","๐Ÿฆ“","๐Ÿฆ","๐Ÿฆง","๐Ÿฆฃ","๐Ÿ˜","๐Ÿฆ›","๐Ÿฆ","๐Ÿช","๐Ÿซ","๐Ÿฆ’","๐Ÿฆ˜","๐Ÿฆฌ","๐Ÿƒ","๐Ÿ‚","๐Ÿ„","๐ŸŽ","๐Ÿ–","๐Ÿ","๐Ÿ‘","๐Ÿฆ™","๐Ÿ","๐ŸฆŒ","๐Ÿ•","๐Ÿฉ","๐Ÿฆฎ","๐Ÿ•โ€๐Ÿฆบ","๐Ÿˆ","๐Ÿˆโ€โฌ›","๐Ÿชถ","๐Ÿ“","๐Ÿฆƒ","๐Ÿฆค","๐Ÿฆš","๐Ÿฆœ","๐Ÿฆข","๐Ÿฆฉ","๐Ÿ•Š","๐Ÿ‡","๐Ÿฆ","๐Ÿฆจ","๐Ÿฆก","๐Ÿฆซ","๐Ÿฆฆ","๐Ÿฆฅ","๐Ÿ","๐Ÿ€","๐Ÿฟ","๐Ÿฆ”","๐Ÿพ","๐Ÿ‰","๐Ÿฒ","๐ŸŒต","๐ŸŽ„","๐ŸŒฒ","๐ŸŒณ","๐ŸŒด","๐Ÿชต","๐ŸŒฑ","๐ŸŒฟ","โ˜˜๏ธ","๐Ÿ€","๐ŸŽ","๐Ÿชด","๐ŸŽ‹","๐Ÿƒ","๐Ÿ‚","๐Ÿ","๐Ÿ„","๐Ÿš","๐Ÿชจ","๐ŸŒพ","๐Ÿ’","๐ŸŒท","๐ŸŒน","๐Ÿฅ€","๐ŸŒบ","๐ŸŒธ","๐ŸŒผ","๐ŸŒป","๐ŸŒž","๐ŸŒ","๐ŸŒ›","๐ŸŒœ","๐ŸŒš","๐ŸŒ•","๐ŸŒ–","๐ŸŒ—","๐ŸŒ˜","๐ŸŒ‘","๐ŸŒ’","๐ŸŒ“","๐ŸŒ”","๐ŸŒ™","๐ŸŒŽ","๐ŸŒ","๐ŸŒ","๐Ÿช","๐Ÿ’ซ","โญ๏ธ","๐ŸŒŸ","โœจ","โšก๏ธ","โ˜„๏ธ","๐Ÿ’ฅ","๐Ÿ”ฅ","๐ŸŒช","๐ŸŒˆ","โ˜€๏ธ","๐ŸŒค","โ›…๏ธ","๐ŸŒฅ","โ˜๏ธ","๐ŸŒฆ","๐ŸŒง","โ›ˆ","๐ŸŒฉ","๐ŸŒจ","โ„๏ธ","โ˜ƒ๏ธ","โ›„๏ธ","๐ŸŒฌ","๐Ÿ’จ","๐Ÿ’ง","๐Ÿ’ฆ","โ˜”๏ธ","โ˜‚๏ธ","๐ŸŒŠ","๐ŸŒซ" +"๐Ÿถ","๐Ÿฑ","๐Ÿญ","๐Ÿน","๐Ÿฐ","๐ŸฆŠ","๐Ÿป","๐Ÿผ","๐Ÿปโ€โ„๏ธ","๐Ÿจ","๐Ÿฏ","๐Ÿฆ","๐Ÿฎ","๐Ÿท","๐Ÿฝ","๐Ÿธ","๐Ÿต","๐Ÿ™ˆ","๐Ÿ™‰","๐Ÿ™Š","๐Ÿ’","๐Ÿ”","๐Ÿง","๐Ÿฆ","๐Ÿค","๐Ÿฃ","๐Ÿฅ","๐Ÿชฟ","๐Ÿฆ†","๐Ÿฆโ€โฌ›๏ธ","๐Ÿฆ…","๐Ÿฆ‰","๐Ÿฆ‡","๐Ÿบ","๐Ÿ—","๐Ÿด","๐Ÿฆ„","๐ŸซŽ","๐Ÿ","๐Ÿชฑ","๐Ÿ›","๐Ÿฆ‹","๐ŸŒ","๐Ÿž","๐Ÿœ","๐Ÿชฐ","๐Ÿชฒ","๐Ÿชณ","๐ŸฆŸ","๐Ÿฆ—","๐Ÿ•ท","๐Ÿ•ธ","๐Ÿฆ‚","๐Ÿข","๐Ÿ","๐ŸฆŽ","๐Ÿฆ–","๐Ÿฆ•","๐Ÿ™","๐Ÿฆ‘","๐Ÿชผ","๐Ÿฆ","๐Ÿฆž","๐Ÿฆ€","๐Ÿก","๐Ÿ ","๐ŸŸ","๐Ÿฌ","๐Ÿณ","๐Ÿ‹","๐Ÿฆˆ","๐Ÿฆญ","๐ŸŠ","๐Ÿ…","๐Ÿ†","๐Ÿฆ“","๐Ÿฆ","๐Ÿฆง","๐Ÿฆฃ","๐Ÿ˜","๐Ÿฆ›","๐Ÿฆ","๐Ÿช","๐Ÿซ","๐Ÿฆ’","๐Ÿฆ˜","๐Ÿฆฌ","๐Ÿƒ","๐Ÿ‚","๐Ÿ„","๐Ÿซ","๐ŸŽ","๐Ÿ–","๐Ÿ","๐Ÿ‘","๐Ÿฆ™","๐Ÿ","๐ŸฆŒ","๐Ÿ•","๐Ÿฉ","๐Ÿฆฎ","๐Ÿ•โ€๐Ÿฆบ","๐Ÿˆ","๐Ÿˆโ€โฌ›","๐Ÿชถ","๐Ÿชฝ","๐Ÿ“","๐Ÿฆƒ","๐Ÿฆค","๐Ÿฆš","๐Ÿฆœ","๐Ÿฆข","๐Ÿฆฉ","๐Ÿ•Š","๐Ÿ‡","๐Ÿฆ","๐Ÿฆจ","๐Ÿฆก","๐Ÿฆซ","๐Ÿฆฆ","๐Ÿฆฅ","๐Ÿ","๐Ÿ€","๐Ÿฟ","๐Ÿฆ”","๐Ÿพ","๐Ÿ‰","๐Ÿฒ","๐ŸŒต","๐ŸŽ„","๐ŸŒฒ","๐ŸŒณ","๐ŸŒด","๐Ÿชต","๐ŸŒฑ","๐ŸŒฟ","โ˜˜๏ธ","๐Ÿ€","๐ŸŽ","๐Ÿชด","๐ŸŽ‹","๐Ÿƒ","๐Ÿ‚","๐Ÿ","๐Ÿชบ","๐Ÿชน","๐Ÿ„","๐Ÿš","๐Ÿชธ","๐Ÿชจ","๐ŸŒพ","๐Ÿ’","๐ŸŒท","๐ŸŒน","๐Ÿฅ€","๐Ÿชป","๐Ÿชท","๐ŸŒบ","๐ŸŒธ","๐ŸŒผ","๐ŸŒป","๐ŸŒž","๐ŸŒ","๐ŸŒ›","๐ŸŒœ","๐ŸŒš","๐ŸŒ•","๐ŸŒ–","๐ŸŒ—","๐ŸŒ˜","๐ŸŒ‘","๐ŸŒ’","๐ŸŒ“","๐ŸŒ”","๐ŸŒ™","๐ŸŒŽ","๐ŸŒ","๐ŸŒ","๐Ÿช","๐Ÿ’ซ","โญ๏ธ","๐ŸŒŸ","โœจ","โšก๏ธ","โ˜„๏ธ","๐Ÿ’ฅ","๐Ÿ”ฅ","๐ŸŒช","๐ŸŒˆ","โ˜€๏ธ","๐ŸŒค","โ›…๏ธ","๐ŸŒฅ","โ˜๏ธ","๐ŸŒฆ","๐ŸŒง","โ›ˆ","๐ŸŒฉ","๐ŸŒจ","โ„๏ธ","โ˜ƒ๏ธ","โ›„๏ธ","๐ŸŒฌ","๐Ÿ’จ","๐Ÿ’ง","๐Ÿ’ฆ","๐Ÿซง","โ˜”๏ธ","โ˜‚๏ธ","๐ŸŒŠ","๐ŸŒซ" -"๐Ÿ","๐ŸŽ","๐Ÿ","๐ŸŠ","๐Ÿ‹","๐ŸŒ","๐Ÿ‰","๐Ÿ‡","๐Ÿ“","๐Ÿซ","๐Ÿˆ","๐Ÿ’","๐Ÿ‘","๐Ÿฅญ","๐Ÿ","๐Ÿฅฅ","๐Ÿฅ","๐Ÿ…","๐Ÿ†","๐Ÿฅ‘","๐Ÿฅฆ","๐Ÿฅฌ","๐Ÿฅ’","๐ŸŒถ","๐Ÿซ‘","๐ŸŒฝ","๐Ÿฅ•","๐Ÿซ’","๐Ÿง„","๐Ÿง…","๐Ÿฅ”","๐Ÿ ","๐Ÿฅ","๐Ÿฅฏ","๐Ÿž","๐Ÿฅ–","๐Ÿฅจ","๐Ÿง€","๐Ÿฅš","๐Ÿณ","๐Ÿงˆ","๐Ÿฅž","๐Ÿง‡","๐Ÿฅ“","๐Ÿฅฉ","๐Ÿ—","๐Ÿ–","๐Ÿฆด","๐ŸŒญ","๐Ÿ”","๐ŸŸ","๐Ÿ•","๐Ÿซ“","๐Ÿฅช","๐Ÿฅ™","๐Ÿง†","๐ŸŒฎ","๐ŸŒฏ","๐Ÿซ”","๐Ÿฅ—","๐Ÿฅ˜","๐Ÿซ•","๐Ÿฅซ","๐Ÿ","๐Ÿœ","๐Ÿฒ","๐Ÿ›","๐Ÿฃ","๐Ÿฑ","๐ŸฅŸ","๐Ÿฆช","๐Ÿค","๐Ÿ™","๐Ÿš","๐Ÿ˜","๐Ÿฅ","๐Ÿฅ ","๐Ÿฅฎ","๐Ÿข","๐Ÿก","๐Ÿง","๐Ÿจ","๐Ÿฆ","๐Ÿฅง","๐Ÿง","๐Ÿฐ","๐ŸŽ‚","๐Ÿฎ","๐Ÿญ","๐Ÿฌ","๐Ÿซ","๐Ÿฟ","๐Ÿฉ","๐Ÿช","๐ŸŒฐ","๐Ÿฅœ","๐Ÿฏ","๐Ÿฅ›","๐Ÿผ","๐Ÿซ–","โ˜•๏ธ","๐Ÿต","๐Ÿงƒ","๐Ÿฅค","๐Ÿง‹","๐Ÿถ","๐Ÿบ","๐Ÿป","๐Ÿฅ‚","๐Ÿท","๐Ÿฅƒ","๐Ÿธ","๐Ÿน","๐Ÿง‰","๐Ÿพ","๐ŸงŠ","๐Ÿฅ„","๐Ÿด","๐Ÿฝ","๐Ÿฅฃ","๐Ÿฅก","๐Ÿฅข","๐Ÿง‚" +"๐Ÿ","๐ŸŽ","๐Ÿ","๐ŸŠ","๐Ÿ‹","๐ŸŒ","๐Ÿ‰","๐Ÿ‡","๐Ÿ“","๐Ÿซ","๐Ÿˆ","๐Ÿ’","๐Ÿ‘","๐Ÿฅญ","๐Ÿ","๐Ÿฅฅ","๐Ÿฅ","๐Ÿ…","๐Ÿ†","๐Ÿฅ‘","๐Ÿซ›","๐Ÿฅฆ","๐Ÿฅฌ","๐Ÿฅ’","๐ŸŒถ","๐Ÿซ‘","๐ŸŒฝ","๐Ÿฅ•","๐Ÿซ’","๐Ÿง„","๐Ÿง…","๐Ÿฅ”","๐Ÿ ","๐Ÿซš","๐Ÿฅ","๐Ÿฅฏ","๐Ÿž","๐Ÿฅ–","๐Ÿฅจ","๐Ÿง€","๐Ÿฅš","๐Ÿณ","๐Ÿงˆ","๐Ÿฅž","๐Ÿง‡","๐Ÿฅ“","๐Ÿฅฉ","๐Ÿ—","๐Ÿ–","๐Ÿฆด","๐ŸŒญ","๐Ÿ”","๐ŸŸ","๐Ÿ•","๐Ÿซ“","๐Ÿฅช","๐Ÿฅ™","๐Ÿง†","๐ŸŒฎ","๐ŸŒฏ","๐Ÿซ”","๐Ÿฅ—","๐Ÿฅ˜","๐Ÿซ•","๐Ÿฅซ","๐Ÿ","๐Ÿœ","๐Ÿฒ","๐Ÿซ™","๐Ÿ›","๐Ÿฃ","๐Ÿฑ","๐ŸฅŸ","๐Ÿฆช","๐Ÿค","๐Ÿ™","๐Ÿš","๐Ÿ˜","๐Ÿฅ","๐Ÿฅ ","๐Ÿฅฎ","๐Ÿข","๐Ÿก","๐Ÿง","๐Ÿจ","๐Ÿฆ","๐Ÿฅง","๐Ÿง","๐Ÿฐ","๐ŸŽ‚","๐Ÿฎ","๐Ÿญ","๐Ÿฌ","๐Ÿซ","๐Ÿฟ","๐Ÿฉ","๐Ÿช","๐ŸŒฐ","๐Ÿฅœ","๐Ÿซ˜","๐Ÿฏ","๐Ÿฅ›","๐Ÿซ—","๐Ÿผ","๐Ÿซ–","โ˜•๏ธ","๐Ÿต","๐Ÿงƒ","๐Ÿฅค","๐Ÿง‹","๐Ÿถ","๐Ÿบ","๐Ÿป","๐Ÿฅ‚","๐Ÿท","๐Ÿฅƒ","๐Ÿธ","๐Ÿน","๐Ÿง‰","๐Ÿพ","๐ŸงŠ","๐Ÿฅ„","๐Ÿด","๐Ÿฝ","๐Ÿฅฃ","๐Ÿฅก","๐Ÿฅข","๐Ÿง‚" -"โšฝ๏ธ","๐Ÿ€","๐Ÿˆ","โšพ๏ธ","๐ŸฅŽ","๐ŸŽพ","๐Ÿ","๐Ÿ‰","๐Ÿฅ","๐ŸŽฑ","๐Ÿช€","๐Ÿ“","๐Ÿธ","๐Ÿ’","๐Ÿ‘","๐Ÿฅ","๐Ÿ","๐Ÿชƒ","๐Ÿฅ…","โ›ณ๏ธ","๐Ÿช","๐Ÿน","๐ŸŽฃ","๐Ÿคฟ","๐ŸฅŠ","๐Ÿฅ‹","๐ŸŽฝ","๐Ÿ›น","๐Ÿ›ผ","๐Ÿ›ท","โ›ธ","๐ŸฅŒ","๐ŸŽฟ","โ›ท","๐Ÿ‚","๐Ÿช‚", +"โšฝ๏ธ","๐Ÿ€","๐Ÿˆ","โšพ๏ธ","๐ŸฅŽ","๐ŸŽพ","๐Ÿ","๐Ÿ‰","๐Ÿฅ","๐ŸŽฑ","๐Ÿช€","๐Ÿ“","๐Ÿธ","๐Ÿ’","๐Ÿ‘","๐Ÿฅ","๐Ÿ","๐Ÿชƒ","๐Ÿฅ…","โ›ณ๏ธ","๐Ÿช","๐Ÿ›","๐Ÿน","๐ŸŽฃ","๐Ÿคฟ","๐ŸฅŠ","๐Ÿฅ‹","๐ŸŽฝ","๐Ÿ›น","๐Ÿ›ผ","๐Ÿ›ท","โ›ธ","๐ŸฅŒ","๐ŸŽฟ","โ›ท","๐Ÿ‚","๐Ÿช‚", "๐Ÿ‹๏ธโ€โ™€๏ธ","๐Ÿ‹๐Ÿปโ€โ™€๏ธ","๐Ÿ‹๐Ÿผโ€โ™€๏ธ","๐Ÿ‹๐Ÿฝโ€โ™€๏ธ","๐Ÿ‹๐Ÿพโ€โ™€๏ธ","๐Ÿ‹๐Ÿฟโ€โ™€๏ธ", "๐Ÿ‹๏ธ","๐Ÿ‹๐Ÿป","๐Ÿ‹๐Ÿผ","๐Ÿ‹๐Ÿฝ","๐Ÿ‹๐Ÿพ","๐Ÿ‹๐Ÿฟ", "๐Ÿ‹๏ธโ€โ™‚๏ธ","๐Ÿ‹๐Ÿปโ€โ™‚๏ธ","๐Ÿ‹๐Ÿผโ€โ™‚๏ธ","๐Ÿ‹๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‹๐Ÿพโ€โ™‚๏ธ","๐Ÿ‹๐Ÿฟโ€โ™‚๏ธ", @@ -306,20 +319,20 @@ "๐Ÿคนโ€โ™€๏ธ","๐Ÿคน๐Ÿปโ€โ™€๏ธ","๐Ÿคน๐Ÿผโ€โ™€๏ธ","๐Ÿคน๐Ÿฝโ€โ™€๏ธ","๐Ÿคน๐Ÿพโ€โ™€๏ธ","๐Ÿคน๐Ÿฟโ€โ™€๏ธ", "๐Ÿคน","๐Ÿคน๐Ÿป","๐Ÿคน๐Ÿผ","๐Ÿคน๐Ÿฝ","๐Ÿคน๐Ÿพ","๐Ÿคน๐Ÿฟ", "๐Ÿคนโ€โ™‚๏ธ","๐Ÿคน๐Ÿปโ€โ™‚๏ธ","๐Ÿคน๐Ÿผโ€โ™‚๏ธ","๐Ÿคน๐Ÿฝโ€โ™‚๏ธ","๐Ÿคน๐Ÿพโ€โ™‚๏ธ","๐Ÿคน๐Ÿฟโ€โ™‚๏ธ", -"๐ŸŽญ","๐Ÿฉฐ","๐ŸŽจ","๐ŸŽฌ","๐ŸŽค","๐ŸŽง","๐ŸŽผ","๐ŸŽน","๐Ÿฅ","๐Ÿช˜","๐ŸŽท","๐ŸŽบ","๐Ÿช—","๐ŸŽธ","๐Ÿช•","๐ŸŽป","๐ŸŽฒ","โ™Ÿ","๐ŸŽฏ","๐ŸŽณ","๐ŸŽฎ","๐ŸŽฐ","๐Ÿงฉ" +"๐ŸŽญ","๐Ÿฉฐ","๐ŸŽจ","๐ŸŽฌ","๐ŸŽค","๐ŸŽง","๐ŸŽผ","๐ŸŽน","๐Ÿช‡","๐Ÿฅ","๐Ÿช˜","๐ŸŽท","๐ŸŽบ","๐Ÿช—","๐ŸŽธ","๐Ÿช•","๐ŸŽป","๐Ÿชˆ","๐ŸŽฒ","โ™Ÿ","๐ŸŽฏ","๐ŸŽณ","๐ŸŽฎ","๐ŸŽฐ","๐Ÿงฉ" -"๐Ÿš—","๐Ÿš•","๐Ÿš™","๐ŸšŒ","๐ŸšŽ","๐ŸŽ","๐Ÿš“","๐Ÿš‘","๐Ÿš’","๐Ÿš","๐Ÿ›ป","๐Ÿšš","๐Ÿš›","๐Ÿšœ","๐Ÿฆฏ","๐Ÿฆฝ","๐Ÿฆผ","๐Ÿ›ด","๐Ÿšฒ","๐Ÿ›ต","๐Ÿ","๐Ÿ›บ","๐Ÿšจ","๐Ÿš”","๐Ÿš","๐Ÿš˜","๐Ÿš–","๐Ÿšก","๐Ÿš ","๐ŸšŸ","๐Ÿšƒ","๐Ÿš‹","๐Ÿšž","๐Ÿš","๐Ÿš„","๐Ÿš…","๐Ÿšˆ","๐Ÿš‚","๐Ÿš†","๐Ÿš‡","๐ŸšŠ","๐Ÿš‰","โœˆ๏ธ","๐Ÿ›ซ","๐Ÿ›ฌ","๐Ÿ›ฉ","๐Ÿ’บ","๐Ÿ›ฐ","๐Ÿš€","๐Ÿ›ธ","๐Ÿš","๐Ÿ›ถ","โ›ต๏ธ","๐Ÿšค","๐Ÿ›ฅ","๐Ÿ›ณ","โ›ด","๐Ÿšข","โš“๏ธ","๐Ÿช","โ›ฝ๏ธ","๐Ÿšง","๐Ÿšฆ","๐Ÿšฅ","๐Ÿš","๐Ÿ—บ","๐Ÿ—ฟ","๐Ÿ—ฝ","๐Ÿ—ผ","๐Ÿฐ","๐Ÿฏ","๐ŸŸ","๐ŸŽก","๐ŸŽข","๐ŸŽ ","โ›ฒ๏ธ","โ›ฑ","๐Ÿ–","๐Ÿ","๐Ÿœ","๐ŸŒ‹","โ›ฐ","๐Ÿ”","๐Ÿ—ป","๐Ÿ•","โ›บ๏ธ","๐Ÿ›–","๐Ÿ ","๐Ÿก","๐Ÿ˜","๐Ÿš","๐Ÿ—","๐Ÿญ","๐Ÿข","๐Ÿฌ","๐Ÿฃ","๐Ÿค","๐Ÿฅ","๐Ÿฆ","๐Ÿจ","๐Ÿช","๐Ÿซ","๐Ÿฉ","๐Ÿ’’","๐Ÿ›","โ›ช๏ธ","๐Ÿ•Œ","๐Ÿ•","๐Ÿ›•","๐Ÿ•‹","โ›ฉ","๐Ÿ›ค","๐Ÿ›ฃ","๐Ÿ—พ","๐ŸŽ‘","๐Ÿž","๐ŸŒ…","๐ŸŒ„","๐ŸŒ ","๐ŸŽ‡","๐ŸŽ†","๐ŸŒ‡","๐ŸŒ†","๐Ÿ™","๐ŸŒƒ","๐ŸŒŒ","๐ŸŒ‰","๐ŸŒ" +"๐Ÿš—","๐Ÿš•","๐Ÿš™","๐ŸšŒ","๐ŸšŽ","๐ŸŽ","๐Ÿš“","๐Ÿš‘","๐Ÿš’","๐Ÿš","๐Ÿ›ป","๐Ÿšš","๐Ÿš›","๐Ÿšœ","๐Ÿฆฏ","๐Ÿฆฝ","๐Ÿฆผ","๐Ÿฉผ","๐Ÿ›ด","๐Ÿšฒ","๐Ÿ›ต","๐Ÿ","๐Ÿ›บ","๐Ÿ›ž","๐Ÿšจ","๐Ÿš”","๐Ÿš","๐Ÿš˜","๐Ÿš–","๐Ÿšก","๐Ÿš ","๐ŸšŸ","๐Ÿšƒ","๐Ÿš‹","๐Ÿšž","๐Ÿš","๐Ÿš„","๐Ÿš…","๐Ÿšˆ","๐Ÿš‚","๐Ÿš†","๐Ÿš‡","๐ŸšŠ","๐Ÿš‰","โœˆ๏ธ","๐Ÿ›ซ","๐Ÿ›ฌ","๐Ÿ›ฉ","๐Ÿ’บ","๐Ÿ›ฐ","๐Ÿš€","๐Ÿ›ธ","๐Ÿš","๐Ÿ›ถ","โ›ต๏ธ","๐Ÿšค","๐Ÿ›ฅ","๐Ÿ›ณ","โ›ด","๐Ÿšข","๐Ÿ›Ÿ","โš“๏ธ","๐Ÿช","โ›ฝ๏ธ","๐Ÿšง","๐Ÿšฆ","๐Ÿšฅ","๐Ÿš","๐Ÿ—บ","๐Ÿ—ฟ","๐Ÿ—ฝ","๐Ÿ—ผ","๐Ÿฐ","๐Ÿฏ","๐ŸŸ","๐ŸŽก","๐ŸŽข","๐ŸŽ ","โ›ฒ๏ธ","โ›ฑ","๐Ÿ–","๐Ÿ","๐Ÿœ","๐ŸŒ‹","โ›ฐ","๐Ÿ”","๐Ÿ—ป","๐Ÿ•","โ›บ๏ธ","๐Ÿ›–","๐Ÿ ","๐Ÿก","๐Ÿ˜","๐Ÿš","๐Ÿ—","๐Ÿญ","๐Ÿข","๐Ÿฌ","๐Ÿฃ","๐Ÿค","๐Ÿฅ","๐Ÿฆ","๐Ÿจ","๐Ÿช","๐Ÿซ","๐Ÿฉ","๐Ÿ’’","๐Ÿ›","โ›ช๏ธ","๐Ÿ•Œ","๐Ÿ•","๐Ÿ›•","๐Ÿ•‹","โ›ฉ","๐Ÿ›ค","๐Ÿ›ฃ","๐Ÿ—พ","๐ŸŽ‘","๐Ÿž","๐ŸŒ…","๐ŸŒ„","๐ŸŒ ","๐ŸŽ‡","๐ŸŽ†","๐ŸŒ‡","๐ŸŒ†","๐Ÿ™","๐ŸŒƒ","๐ŸŒŒ","๐ŸŒ‰","๐ŸŒ" -"โŒš๏ธ","๐Ÿ“ฑ","๐Ÿ“ฒ","๐Ÿ’ป","โŒจ๏ธ","๐Ÿ–ฅ","๐Ÿ–จ","๐Ÿ–ฑ","๐Ÿ–ฒ","๐Ÿ•น","๐Ÿ—œ","๐Ÿ’ฝ","๐Ÿ’พ","๐Ÿ’ฟ","๐Ÿ“€","๐Ÿ“ผ","๐Ÿ“ท","๐Ÿ“ธ","๐Ÿ“น","๐ŸŽฅ","๐Ÿ“ฝ","๐ŸŽž","๐Ÿ“ž","โ˜Ž๏ธ","๐Ÿ“Ÿ","๐Ÿ“ ","๐Ÿ“บ","๐Ÿ“ป","๐ŸŽ™","๐ŸŽš","๐ŸŽ›","๐Ÿงญ","โฑ","โฒ","โฐ","๐Ÿ•ฐ","โŒ›๏ธ","โณ","๐Ÿ“ก","๐Ÿ”‹","๐Ÿ”Œ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ•ฏ","๐Ÿช”","๐Ÿงฏ","๐Ÿ›ข","๐Ÿ’ธ","๐Ÿ’ต","๐Ÿ’ด","๐Ÿ’ถ","๐Ÿ’ท","๐Ÿช™","๐Ÿ’ฐ","๐Ÿ’ณ","๐Ÿ’Ž","โš–๏ธ","๐Ÿชœ","๐Ÿงฐ","๐Ÿช›","๐Ÿ”ง","๐Ÿ”จ","โš’","๐Ÿ› ","โ›","๐Ÿชš","๐Ÿ”ฉ","โš™๏ธ","๐Ÿชค","๐Ÿงฑ","โ›“","๐Ÿงฒ","๐Ÿ”ซ","๐Ÿ’ฃ","๐Ÿงจ","๐Ÿช“","๐Ÿ”ช","๐Ÿ—ก","โš”๏ธ","๐Ÿ›ก","๐Ÿšฌ","โšฐ๏ธ","๐Ÿชฆ","โšฑ๏ธ","๐Ÿบ","๐Ÿ”ฎ","๐Ÿ“ฟ","๐Ÿงฟ","๐Ÿ’ˆ","โš—๏ธ","๐Ÿ”ญ","๐Ÿ”ฌ","๐Ÿ•ณ","๐Ÿฉน","๐Ÿฉบ","๐Ÿ’Š","๐Ÿ’‰","๐Ÿฉธ","๐Ÿงฌ","๐Ÿฆ ","๐Ÿงซ","๐Ÿงช","๐ŸŒก","๐Ÿงน","๐Ÿช ","๐Ÿงบ","๐Ÿงป","๐Ÿšฝ","๐Ÿšฐ","๐Ÿšฟ","๐Ÿ›", +"โŒš๏ธ","๐Ÿ“ฑ","๐Ÿ“ฒ","๐Ÿ’ป","โŒจ๏ธ","๐Ÿ–ฅ","๐Ÿ–จ","๐Ÿ–ฑ","๐Ÿ–ฒ","๐Ÿ•น","๐Ÿ—œ","๐Ÿ’ฝ","๐Ÿ’พ","๐Ÿ’ฟ","๐Ÿ“€","๐Ÿ“ผ","๐Ÿ“ท","๐Ÿ“ธ","๐Ÿ“น","๐ŸŽฅ","๐Ÿ“ฝ","๐ŸŽž","๐Ÿ“ž","โ˜Ž๏ธ","๐Ÿ“Ÿ","๐Ÿ“ ","๐Ÿ“บ","๐Ÿ“ป","๐ŸŽ™","๐ŸŽš","๐ŸŽ›","๐Ÿงญ","โฑ","โฒ","โฐ","๐Ÿ•ฐ","โŒ›๏ธ","โณ","๐Ÿ“ก","๐Ÿ”‹","๐Ÿชซ","๐Ÿ”Œ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ•ฏ","๐Ÿช”","๐Ÿงฏ","๐Ÿ›ข","๐Ÿ’ธ","๐Ÿ’ต","๐Ÿ’ด","๐Ÿ’ถ","๐Ÿ’ท","๐Ÿช™","๐Ÿ’ฐ","๐Ÿ’ณ","๐Ÿชช","๐Ÿ’Ž","โš–๏ธ","๐Ÿชœ","๐Ÿงฐ","๐Ÿช›","๐Ÿ”ง","๐Ÿ”จ","โš’","๐Ÿ› ","โ›","๐Ÿชš","๐Ÿ”ฉ","โš™๏ธ","๐Ÿชค","๐Ÿงฑ","โ›“","๐Ÿงฒ","๐Ÿ”ซ","๐Ÿ’ฃ","๐Ÿงจ","๐Ÿช“","๐Ÿ”ช","๐Ÿ—ก","โš”๏ธ","๐Ÿ›ก","๐Ÿšฌ","โšฐ๏ธ","๐Ÿชฆ","โšฑ๏ธ","๐Ÿบ","๐Ÿ”ฎ","๐Ÿ“ฟ","๐Ÿงฟ","๐Ÿชฌ","๐Ÿ’ˆ","โš—๏ธ","๐Ÿ”ญ","๐Ÿ”ฌ","๐Ÿ•ณ","๐Ÿฉป","๐Ÿฉน","๐Ÿฉบ","๐Ÿ’Š","๐Ÿ’‰","๐Ÿฉธ","๐Ÿงฌ","๐Ÿฆ ","๐Ÿงซ","๐Ÿงช","๐ŸŒก","๐Ÿงน","๐Ÿช ","๐Ÿงบ","๐Ÿงป","๐Ÿšฝ","๐Ÿšฐ","๐Ÿšฟ","๐Ÿ›", "๐Ÿ›€","๐Ÿ›€๐Ÿป","๐Ÿ›€๐Ÿผ","๐Ÿ›€๐Ÿฝ","๐Ÿ›€๐Ÿพ","๐Ÿ›€๐Ÿฟ", -"๐Ÿงผ","๐Ÿชฅ","๐Ÿช’","๐Ÿงฝ","๐Ÿชฃ","๐Ÿงด","๐Ÿ›Ž","๐Ÿ”‘","๐Ÿ—","๐Ÿšช","๐Ÿช‘","๐Ÿ›‹","๐Ÿ›","๐Ÿ›Œ","๐Ÿงธ","๐Ÿช†","๐Ÿ–ผ","๐Ÿชž","๐ŸชŸ","๐Ÿ›","๐Ÿ›’","๐ŸŽ","๐ŸŽˆ","๐ŸŽ","๐ŸŽ€","๐Ÿช„","๐Ÿช…","๐ŸŽŠ","๐ŸŽ‰","๐ŸŽŽ","๐Ÿฎ","๐ŸŽ","๐Ÿงง","โœ‰๏ธ","๐Ÿ“ฉ","๐Ÿ“จ","๐Ÿ“ง","๐Ÿ’Œ","๐Ÿ“ฅ","๐Ÿ“ค","๐Ÿ“ฆ","๐Ÿท","๐Ÿชง","๐Ÿ“ช","๐Ÿ“ซ","๐Ÿ“ฌ","๐Ÿ“ญ","๐Ÿ“ฎ","๐Ÿ“ฏ","๐Ÿ“œ","๐Ÿ“ƒ","๐Ÿ“„","๐Ÿ“‘","๐Ÿงพ","๐Ÿ“Š","๐Ÿ“ˆ","๐Ÿ“‰","๐Ÿ—’","๐Ÿ—“","๐Ÿ“†","๐Ÿ“…","๐Ÿ—‘","๐Ÿ“‡","๐Ÿ—ƒ","๐Ÿ—ณ","๐Ÿ—„","๐Ÿ“‹","๐Ÿ“","๐Ÿ“‚","๐Ÿ—‚","๐Ÿ—ž","๐Ÿ“ฐ","๐Ÿ““","๐Ÿ“”","๐Ÿ“’","๐Ÿ“•","๐Ÿ“—","๐Ÿ“˜","๐Ÿ“™","๐Ÿ“š","๐Ÿ“–","๐Ÿ”–","๐Ÿงท","๐Ÿ”—","๐Ÿ“Ž","๐Ÿ–‡","๐Ÿ“","๐Ÿ“","๐Ÿงฎ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ–Š","๐Ÿ–‹","โœ’๏ธ","๐Ÿ–Œ","๐Ÿ–","๐Ÿ“","โœ๏ธ","๐Ÿ”","๐Ÿ”Ž","๐Ÿ”","๐Ÿ”","๐Ÿ”’","๐Ÿ”“" +"๐Ÿงผ","๐Ÿชฅ","๐Ÿช’","๐Ÿชฎ","๐Ÿงฝ","๐Ÿชฃ","๐Ÿงด","๐Ÿ›Ž","๐Ÿ”‘","๐Ÿ—","๐Ÿšช","๐Ÿช‘","๐Ÿ›‹","๐Ÿ›","๐Ÿ›Œ","๐Ÿงธ","๐Ÿช†","๐Ÿ–ผ","๐Ÿชž","๐ŸชŸ","๐Ÿ›","๐Ÿ›’","๐ŸŽ","๐ŸŽˆ","๐ŸŽ","๐ŸŽ€","๐Ÿช„","๐Ÿช…","๐ŸŽŠ","๐ŸŽ‰","๐ŸŽŽ","๐Ÿชญ","๐Ÿฎ","๐ŸŽ","๐Ÿชฉ","๐Ÿงง","โœ‰๏ธ","๐Ÿ“ฉ","๐Ÿ“จ","๐Ÿ“ง","๐Ÿ’Œ","๐Ÿ“ฅ","๐Ÿ“ค","๐Ÿ“ฆ","๐Ÿท","๐Ÿชง","๐Ÿ“ช","๐Ÿ“ซ","๐Ÿ“ฌ","๐Ÿ“ญ","๐Ÿ“ฎ","๐Ÿ“ฏ","๐Ÿ“œ","๐Ÿ“ƒ","๐Ÿ“„","๐Ÿ“‘","๐Ÿงพ","๐Ÿ“Š","๐Ÿ“ˆ","๐Ÿ“‰","๐Ÿ—’","๐Ÿ—“","๐Ÿ“†","๐Ÿ“…","๐Ÿ—‘","๐Ÿ“‡","๐Ÿ—ƒ","๐Ÿ—ณ","๐Ÿ—„","๐Ÿ“‹","๐Ÿ“","๐Ÿ“‚","๐Ÿ—‚","๐Ÿ—ž","๐Ÿ“ฐ","๐Ÿ““","๐Ÿ“”","๐Ÿ“’","๐Ÿ“•","๐Ÿ“—","๐Ÿ“˜","๐Ÿ“™","๐Ÿ“š","๐Ÿ“–","๐Ÿ”–","๐Ÿงท","๐Ÿ”—","๐Ÿ“Ž","๐Ÿ–‡","๐Ÿ“","๐Ÿ“","๐Ÿงฎ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ–Š","๐Ÿ–‹","โœ’๏ธ","๐Ÿ–Œ","๐Ÿ–","๐Ÿ“","โœ๏ธ","๐Ÿ”","๐Ÿ”Ž","๐Ÿ”","๐Ÿ”","๐Ÿ”’","๐Ÿ”“" -"โค๏ธ","๐Ÿงก","๐Ÿ’›","๐Ÿ’š","๐Ÿ’™","๐Ÿ’œ","๐Ÿ–ค","๐Ÿค","๐ŸคŽ","๐Ÿ’”","โค๏ธโ€๐Ÿ”ฅ","โค๏ธโ€๐Ÿฉน","โฃ๏ธ","๐Ÿ’•","๐Ÿ’ž","๐Ÿ’“","๐Ÿ’—","๐Ÿ’–","๐Ÿ’˜","๐Ÿ’","๐Ÿ’Ÿ","โ˜ฎ๏ธ","โœ๏ธ","โ˜ช๏ธ","๐Ÿ•‰","โ˜ธ๏ธ","โœก๏ธ","๐Ÿ”ฏ","๐Ÿ•Ž","โ˜ฏ๏ธ","โ˜ฆ๏ธ","๐Ÿ›","โ›Ž","โ™ˆ๏ธ","โ™‰๏ธ","โ™Š๏ธ","โ™‹๏ธ","โ™Œ๏ธ","โ™๏ธ","โ™Ž๏ธ","โ™๏ธ","โ™๏ธ","โ™‘๏ธ","โ™’๏ธ","โ™“๏ธ","๐Ÿ†”","โš›๏ธ","๐Ÿ‰‘","โ˜ข๏ธ","โ˜ฃ๏ธ","๐Ÿ“ด","๐Ÿ“ณ","๐Ÿˆถ","๐Ÿˆš๏ธ","๐Ÿˆธ","๐Ÿˆบ","๐Ÿˆท๏ธ","โœด๏ธ","๐Ÿ†š","๐Ÿ’ฎ","๐Ÿ‰","ใŠ™๏ธ","ใŠ—๏ธ","๐Ÿˆด","๐Ÿˆต","๐Ÿˆน","๐Ÿˆฒ","๐Ÿ…ฐ๏ธ","๐Ÿ…ฑ๏ธ","๐Ÿ†Ž","๐Ÿ†‘","๐Ÿ…พ๏ธ","๐Ÿ†˜","โŒ","โญ•๏ธ","๐Ÿ›‘","โ›”๏ธ","๐Ÿ“›","๐Ÿšซ","๐Ÿ’ฏ","๐Ÿ’ข","โ™จ๏ธ","๐Ÿšท","๐Ÿšฏ","๐Ÿšณ","๐Ÿšฑ","๐Ÿ”ž","๐Ÿ“ต","๐Ÿšญ","โ—๏ธ","โ•","โ“","โ”","โ€ผ๏ธ","โ‰๏ธ","๐Ÿ”…","๐Ÿ”†","ใ€ฝ๏ธ","โš ๏ธ","๐Ÿšธ","๐Ÿ”ฑ","โšœ๏ธ","๐Ÿ”ฐ","โ™ป๏ธ","โœ…","๐Ÿˆฏ๏ธ","๐Ÿ’น","โ‡๏ธ","โœณ๏ธ","โŽ","๐ŸŒ","๐Ÿ’ ","โ“‚๏ธ","๐ŸŒ€","๐Ÿ’ค","๐Ÿง","๐Ÿšพ","โ™ฟ๏ธ","๐Ÿ…ฟ๏ธ","๐Ÿ›—","๐Ÿˆณ","๐Ÿˆ‚๏ธ","๐Ÿ›‚","๐Ÿ›ƒ","๐Ÿ›„","๐Ÿ›…","๐Ÿšน","๐Ÿšบ","๐Ÿšผ","โšง","๐Ÿšป","๐Ÿšฎ","๐ŸŽฆ","๐Ÿ“ถ","๐Ÿˆ","๐Ÿ”ฃ","โ„น๏ธ","๐Ÿ”ค","๐Ÿ”ก","๐Ÿ” ","๐Ÿ†–","๐Ÿ†—","๐Ÿ†™","๐Ÿ†’","๐Ÿ†•","๐Ÿ†“","0๏ธโƒฃ","1๏ธโƒฃ","2๏ธโƒฃ","3๏ธโƒฃ","4๏ธโƒฃ","5๏ธโƒฃ","6๏ธโƒฃ","7๏ธโƒฃ","8๏ธโƒฃ","9๏ธโƒฃ","๐Ÿ”Ÿ","๐Ÿ”ข","#๏ธโƒฃ","*๏ธโƒฃ","โ๏ธ","โ–ถ๏ธ","โธ","โฏ","โน","โบ","โญ","โฎ","โฉ","โช","โซ","โฌ","โ—€๏ธ","๐Ÿ”ผ","๐Ÿ”ฝ","โžก๏ธ","โฌ…๏ธ","โฌ†๏ธ","โฌ‡๏ธ","โ†—๏ธ","โ†˜๏ธ","โ†™๏ธ","โ†–๏ธ","โ†•๏ธ","โ†”๏ธ","โ†ช๏ธ","โ†ฉ๏ธ","โคด๏ธ","โคต๏ธ","๐Ÿ”€","๐Ÿ”","๐Ÿ”‚","๐Ÿ”„","๐Ÿ”ƒ","๐ŸŽต","๐ŸŽถ","โž•","โž–","โž—","โœ–๏ธ","โ™พ","๐Ÿ’ฒ","๐Ÿ’ฑ","โ„ข๏ธ","ยฉ๏ธ","ยฎ๏ธ","๐Ÿ‘โ€๐Ÿ—จ","๐Ÿ”š","๐Ÿ”™","๐Ÿ”›","๐Ÿ”","๐Ÿ”œ","ใ€ฐ๏ธ","โžฐ","โžฟ","โœ”๏ธ","โ˜‘๏ธ","๐Ÿ”˜","๐Ÿ”ด","๐ŸŸ ","๐ŸŸก","๐ŸŸข","๐Ÿ”ต","๐ŸŸฃ","โšซ๏ธ","โšช๏ธ","๐ŸŸค","๐Ÿ”บ","๐Ÿ”ป","๐Ÿ”ธ","๐Ÿ”น","๐Ÿ”ถ","๐Ÿ”ท","๐Ÿ”ณ","๐Ÿ”ฒ","โ–ช๏ธ","โ–ซ๏ธ","โ—พ๏ธ","โ—ฝ๏ธ","โ—ผ๏ธ","โ—ป๏ธ","๐ŸŸฅ","๐ŸŸง","๐ŸŸจ","๐ŸŸฉ","๐ŸŸฆ","๐ŸŸช","โฌ›๏ธ","โฌœ๏ธ","๐ŸŸซ","๐Ÿ”ˆ","๐Ÿ”‡","๐Ÿ”‰","๐Ÿ”Š","๐Ÿ””","๐Ÿ”•","๐Ÿ“ฃ","๐Ÿ“ข","๐Ÿ’ฌ","๐Ÿ’ญ","๐Ÿ—ฏ","โ™ ๏ธ","โ™ฃ๏ธ","โ™ฅ๏ธ","โ™ฆ๏ธ","๐Ÿƒ","๐ŸŽด","๐Ÿ€„๏ธ","๐Ÿ•","๐Ÿ•‘","๐Ÿ•’","๐Ÿ•“","๐Ÿ•”","๐Ÿ••","๐Ÿ•–","๐Ÿ•—","๐Ÿ•˜","๐Ÿ•™","๐Ÿ•š","๐Ÿ•›","๐Ÿ•œ","๐Ÿ•","๐Ÿ•ž","๐Ÿ•Ÿ","๐Ÿ• ","๐Ÿ•ก","๐Ÿ•ข","๐Ÿ•ฃ","๐Ÿ•ค","๐Ÿ•ฅ","๐Ÿ•ฆ","๐Ÿ•ง" +"๐Ÿฉท","โค๏ธ","๐Ÿงก","๐Ÿ’›","๐Ÿ’š","๐Ÿฉต","๐Ÿ’™","๐Ÿ’œ","๐Ÿ–ค","๐Ÿฉถ","๐Ÿค","๐ŸคŽ","๐Ÿ’”","โค๏ธโ€๐Ÿ”ฅ","โค๏ธโ€๐Ÿฉน","โฃ๏ธ","๐Ÿ’•","๐Ÿ’ž","๐Ÿ’“","๐Ÿ’—","๐Ÿ’–","๐Ÿ’˜","๐Ÿ’","๐Ÿ’Ÿ","โ˜ฎ๏ธ","โœ๏ธ","โ˜ช๏ธ","๐Ÿ•‰","โ˜ธ๏ธ","๐Ÿชฏ","โœก๏ธ","๐Ÿ”ฏ","๐Ÿ•Ž","โ˜ฏ๏ธ","โ˜ฆ๏ธ","๐Ÿ›","โ›Ž","โ™ˆ๏ธ","โ™‰๏ธ","โ™Š๏ธ","โ™‹๏ธ","โ™Œ๏ธ","โ™๏ธ","โ™Ž๏ธ","โ™๏ธ","โ™๏ธ","โ™‘๏ธ","โ™’๏ธ","โ™“๏ธ","๐Ÿ†”","โš›๏ธ","๐Ÿ‰‘","โ˜ข๏ธ","โ˜ฃ๏ธ","๐Ÿ“ด","๐Ÿ“ณ","๐Ÿˆถ","๐Ÿˆš๏ธ","๐Ÿˆธ","๐Ÿˆบ","๐Ÿˆท๏ธ","โœด๏ธ","๐Ÿ†š","๐Ÿ’ฎ","๐Ÿ‰","ใŠ™๏ธ","ใŠ—๏ธ","๐Ÿˆด","๐Ÿˆต","๐Ÿˆน","๐Ÿˆฒ","๐Ÿ…ฐ๏ธ","๐Ÿ…ฑ๏ธ","๐Ÿ†Ž","๐Ÿ†‘","๐Ÿ…พ๏ธ","๐Ÿ†˜","โŒ","โญ•๏ธ","๐Ÿ›‘","โ›”๏ธ","๐Ÿ“›","๐Ÿšซ","๐Ÿ’ฏ","๐Ÿ’ข","โ™จ๏ธ","๐Ÿšท","๐Ÿšฏ","๐Ÿšณ","๐Ÿšฑ","๐Ÿ”ž","๐Ÿ“ต","๐Ÿšญ","โ—๏ธ","โ•","โ“","โ”","โ€ผ๏ธ","โ‰๏ธ","๐Ÿ”…","๐Ÿ”†","ใ€ฝ๏ธ","โš ๏ธ","๐Ÿšธ","๐Ÿ”ฑ","โšœ๏ธ","๐Ÿ”ฐ","โ™ป๏ธ","โœ…","๐Ÿˆฏ๏ธ","๐Ÿ’น","โ‡๏ธ","โœณ๏ธ","โŽ","๐ŸŒ","๐Ÿ’ ","โ“‚๏ธ","๐ŸŒ€","๐Ÿ’ค","๐Ÿง","๐Ÿšพ","โ™ฟ๏ธ","๐Ÿ…ฟ๏ธ","๐Ÿ›—","๐Ÿˆณ","๐Ÿˆ‚๏ธ","๐Ÿ›‚","๐Ÿ›ƒ","๐Ÿ›„","๐Ÿ›…","๐Ÿ›œ","๐Ÿšน","๐Ÿšบ","๐Ÿšผ","โšง","๐Ÿšป","๐Ÿšฎ","๐ŸŽฆ","๐Ÿ“ถ","๐Ÿˆ","๐Ÿ”ฃ","โ„น๏ธ","๐Ÿ”ค","๐Ÿ”ก","๐Ÿ” ","๐Ÿ†–","๐Ÿ†—","๐Ÿ†™","๐Ÿ†’","๐Ÿ†•","๐Ÿ†“","0๏ธโƒฃ","1๏ธโƒฃ","2๏ธโƒฃ","3๏ธโƒฃ","4๏ธโƒฃ","5๏ธโƒฃ","6๏ธโƒฃ","7๏ธโƒฃ","8๏ธโƒฃ","9๏ธโƒฃ","๐Ÿ”Ÿ","๐Ÿ”ข","#๏ธโƒฃ","*๏ธโƒฃ","โ๏ธ","โ–ถ๏ธ","โธ","โฏ","โน","โบ","โญ","โฎ","โฉ","โช","โซ","โฌ","โ—€๏ธ","๐Ÿ”ผ","๐Ÿ”ฝ","โžก๏ธ","โฌ…๏ธ","โฌ†๏ธ","โฌ‡๏ธ","โ†—๏ธ","โ†˜๏ธ","โ†™๏ธ","โ†–๏ธ","โ†•๏ธ","โ†”๏ธ","โ†ช๏ธ","โ†ฉ๏ธ","โคด๏ธ","โคต๏ธ","๐Ÿ”€","๐Ÿ”","๐Ÿ”‚","๐Ÿ”„","๐Ÿ”ƒ","๐ŸŽต","๐ŸŽถ","โž•","โž–","โž—","โœ–๏ธ","๐ŸŸฐ","โ™พ","๐Ÿ’ฒ","๐Ÿ’ฑ","โ„ข๏ธ","ยฉ๏ธ","ยฎ๏ธ","๐Ÿ‘โ€๐Ÿ—จ","๐Ÿ”š","๐Ÿ”™","๐Ÿ”›","๐Ÿ”","๐Ÿ”œ","ใ€ฐ๏ธ","โžฐ","โžฟ","โœ”๏ธ","โ˜‘๏ธ","๐Ÿ”˜","๐Ÿ”ด","๐ŸŸ ","๐ŸŸก","๐ŸŸข","๐Ÿ”ต","๐ŸŸฃ","โšซ๏ธ","โšช๏ธ","๐ŸŸค","๐Ÿ”บ","๐Ÿ”ป","๐Ÿ”ธ","๐Ÿ”น","๐Ÿ”ถ","๐Ÿ”ท","๐Ÿ”ณ","๐Ÿ”ฒ","โ–ช๏ธ","โ–ซ๏ธ","โ—พ๏ธ","โ—ฝ๏ธ","โ—ผ๏ธ","โ—ป๏ธ","๐ŸŸฅ","๐ŸŸง","๐ŸŸจ","๐ŸŸฉ","๐ŸŸฆ","๐ŸŸช","โฌ›๏ธ","โฌœ๏ธ","๐ŸŸซ","๐Ÿ”ˆ","๐Ÿ”‡","๐Ÿ”‰","๐Ÿ”Š","๐Ÿ””","๐Ÿ”•","๐Ÿ“ฃ","๐Ÿ“ข","๐Ÿ’ฌ","๐Ÿ’ญ","๐Ÿ—ฏ","โ™ ๏ธ","โ™ฃ๏ธ","โ™ฅ๏ธ","โ™ฆ๏ธ","๐Ÿƒ","๐ŸŽด","๐Ÿ€„๏ธ","๐Ÿ•","๐Ÿ•‘","๐Ÿ•’","๐Ÿ•“","๐Ÿ•”","๐Ÿ••","๐Ÿ•–","๐Ÿ•—","๐Ÿ•˜","๐Ÿ•™","๐Ÿ•š","๐Ÿ•›","๐Ÿ•œ","๐Ÿ•","๐Ÿ•ž","๐Ÿ•Ÿ","๐Ÿ• ","๐Ÿ•ก","๐Ÿ•ข","๐Ÿ•ฃ","๐Ÿ•ค","๐Ÿ•ฅ","๐Ÿ•ฆ","๐Ÿ•ง" "๐Ÿณ๏ธ","๐Ÿด","๐Ÿดโ€โ˜ ๏ธ","๐Ÿ","๐Ÿšฉ","๐Ÿณ๏ธโ€๐ŸŒˆ","๐Ÿณ๏ธโ€โšง๏ธ","๐Ÿ‡บ๐Ÿ‡ณ","๐Ÿ‡ฆ๐Ÿ‡ซ","๐Ÿ‡ฆ๐Ÿ‡ฝ","๐Ÿ‡ฆ๐Ÿ‡ฑ","๐Ÿ‡ฉ๐Ÿ‡ฟ","๐Ÿ‡ฆ๐Ÿ‡ธ","๐Ÿ‡ฆ๐Ÿ‡ฉ","๐Ÿ‡ฆ๐Ÿ‡ด","๐Ÿ‡ฆ๐Ÿ‡ฎ","๐Ÿ‡ฆ๐Ÿ‡ถ","๐Ÿ‡ฆ๐Ÿ‡ฌ","๐Ÿ‡ฆ๐Ÿ‡ท","๐Ÿ‡ฆ๐Ÿ‡ฒ","๐Ÿ‡ฆ๐Ÿ‡ผ","๐Ÿ‡ฆ๐Ÿ‡บ","๐Ÿ‡ฆ๐Ÿ‡น","๐Ÿ‡ฆ๐Ÿ‡ฟ","๐Ÿ‡ง๐Ÿ‡ธ","๐Ÿ‡ง๐Ÿ‡ญ","๐Ÿ‡ง๐Ÿ‡ฉ","๐Ÿ‡ง๐Ÿ‡ง","๐Ÿ‡ง๐Ÿ‡พ","๐Ÿ‡ง๐Ÿ‡ช","๐Ÿ‡ง๐Ÿ‡ฟ","๐Ÿ‡ง๐Ÿ‡ฏ","๐Ÿ‡ง๐Ÿ‡ฒ","๐Ÿ‡ง๐Ÿ‡น","๐Ÿ‡ง๐Ÿ‡ด","๐Ÿ‡ง๐Ÿ‡ฆ","๐Ÿ‡ง๐Ÿ‡ผ","๐Ÿ‡ง๐Ÿ‡ท","๐Ÿ‡ป๐Ÿ‡ฌ","๐Ÿ‡ง๐Ÿ‡ณ","๐Ÿ‡ง๐Ÿ‡ฌ","๐Ÿ‡ง๐Ÿ‡ซ","๐Ÿ‡ง๐Ÿ‡ฎ","๐Ÿ‡ฐ๐Ÿ‡ญ","๐Ÿ‡จ๐Ÿ‡ฒ","๐Ÿ‡จ๐Ÿ‡ฆ","๐Ÿ‡ฎ๐Ÿ‡จ","๐Ÿ‡จ๐Ÿ‡ป","๐Ÿ‡ง๐Ÿ‡ถ","๐Ÿ‡ฐ๐Ÿ‡พ","๐Ÿ‡จ๐Ÿ‡ซ","๐Ÿ‡น๐Ÿ‡ฉ","๐Ÿ‡ฎ๐Ÿ‡ด","๐Ÿ‡จ๐Ÿ‡ฑ","๐Ÿ‡จ๐Ÿ‡ณ","๐Ÿ‡จ๐Ÿ‡ฝ","๐Ÿ‡จ๐Ÿ‡จ","๐Ÿ‡จ๐Ÿ‡ด","๐Ÿ‡ฐ๐Ÿ‡ฒ","๐Ÿ‡จ๐Ÿ‡ฌ","๐Ÿ‡จ๐Ÿ‡ฉ","๐Ÿ‡จ๐Ÿ‡ฐ","๐Ÿ‡จ๐Ÿ‡ท","๐Ÿ‡จ๐Ÿ‡ฎ","๐Ÿ‡ญ๐Ÿ‡ท","๐Ÿ‡จ๐Ÿ‡บ","๐Ÿ‡จ๐Ÿ‡ผ","๐Ÿ‡จ๐Ÿ‡พ","๐Ÿ‡จ๐Ÿ‡ฟ","๐Ÿ‡ฉ๐Ÿ‡ฐ","๐Ÿ‡ฉ๐Ÿ‡ฏ","๐Ÿ‡ฉ๐Ÿ‡ฒ","๐Ÿ‡ฉ๐Ÿ‡ด","๐Ÿ‡ช๐Ÿ‡จ","๐Ÿ‡ช๐Ÿ‡ฌ","๐Ÿ‡ธ๐Ÿ‡ป","๐Ÿ‡ฌ๐Ÿ‡ถ","๐Ÿ‡ช๐Ÿ‡ท","๐Ÿ‡ช๐Ÿ‡ช","๐Ÿ‡ธ๐Ÿ‡ฟ","๐Ÿ‡ช๐Ÿ‡น","๐Ÿ‡ช๐Ÿ‡บ","๐Ÿ‡ซ๐Ÿ‡ฐ","๐Ÿ‡ซ๐Ÿ‡ด","๐Ÿ‡ซ๐Ÿ‡ฏ","๐Ÿ‡ซ๐Ÿ‡ฎ","๐Ÿ‡ซ๐Ÿ‡ท","๐Ÿ‡ฌ๐Ÿ‡ซ","๐Ÿ‡ต๐Ÿ‡ซ","๐Ÿ‡น๐Ÿ‡ซ","๐Ÿ‡ฌ๐Ÿ‡ฆ","๐Ÿ‡ฌ๐Ÿ‡ฒ","๐Ÿ‡ฌ๐Ÿ‡ช","๐Ÿ‡ฉ๐Ÿ‡ช","๐Ÿ‡ฌ๐Ÿ‡ญ","๐Ÿ‡ฌ๐Ÿ‡ฎ","๐Ÿ‡ฌ๐Ÿ‡ท","๐Ÿ‡ฌ๐Ÿ‡ฑ","๐Ÿ‡ฌ๐Ÿ‡ฉ","๐Ÿ‡ฌ๐Ÿ‡ต","๐Ÿ‡ฌ๐Ÿ‡บ","๐Ÿ‡ฌ๐Ÿ‡น","๐Ÿ‡ฌ๐Ÿ‡ฌ","๐Ÿ‡ฌ๐Ÿ‡ณ","๐Ÿ‡ฌ๐Ÿ‡ผ","๐Ÿ‡ฌ๐Ÿ‡พ","๐Ÿ‡ญ๐Ÿ‡น","๐Ÿ‡ญ๐Ÿ‡ณ","๐Ÿ‡ญ๐Ÿ‡ฐ","๐Ÿ‡ญ๐Ÿ‡บ","๐Ÿ‡ฎ๐Ÿ‡ธ","๐Ÿ‡ฎ๐Ÿ‡ณ","๐Ÿ‡ฎ๐Ÿ‡ฉ","๐Ÿ‡ฎ๐Ÿ‡ท","๐Ÿ‡ฎ๐Ÿ‡ถ","๐Ÿ‡ฎ๐Ÿ‡ช","๐Ÿ‡ฎ๐Ÿ‡ฒ","๐Ÿ‡ฎ๐Ÿ‡ฑ","๐Ÿ‡ฎ๐Ÿ‡น","๐Ÿ‡ฏ๐Ÿ‡ฒ","๐Ÿ‡ฏ๐Ÿ‡ต","๐ŸŽŒ","๐Ÿ‡ฏ๐Ÿ‡ช","๐Ÿ‡ฏ๐Ÿ‡ด","๐Ÿ‡ฐ๐Ÿ‡ฟ","๐Ÿ‡ฐ๐Ÿ‡ช","๐Ÿ‡ฐ๐Ÿ‡ฎ","๐Ÿ‡ฝ๐Ÿ‡ฐ","๐Ÿ‡ฐ๐Ÿ‡ผ","๐Ÿ‡ฐ๐Ÿ‡ฌ","๐Ÿ‡ฑ๐Ÿ‡ฆ","๐Ÿ‡ฑ๐Ÿ‡ป","๐Ÿ‡ฑ๐Ÿ‡ง","๐Ÿ‡ฑ๐Ÿ‡ธ","๐Ÿ‡ฑ๐Ÿ‡ท","๐Ÿ‡ฑ๐Ÿ‡พ","๐Ÿ‡ฑ๐Ÿ‡ฎ","๐Ÿ‡ฑ๐Ÿ‡น","๐Ÿ‡ฑ๐Ÿ‡บ","๐Ÿ‡ฒ๐Ÿ‡ด","๐Ÿ‡ฒ๐Ÿ‡ฌ","๐Ÿ‡ฒ๐Ÿ‡ผ","๐Ÿ‡ฒ๐Ÿ‡พ","๐Ÿ‡ฒ๐Ÿ‡ป","๐Ÿ‡ฒ๐Ÿ‡ฑ","๐Ÿ‡ฒ๐Ÿ‡น","๐Ÿ‡ฒ๐Ÿ‡ญ","๐Ÿ‡ฒ๐Ÿ‡ถ","๐Ÿ‡ฒ๐Ÿ‡ท","๐Ÿ‡ฒ๐Ÿ‡บ","๐Ÿ‡พ๐Ÿ‡น","๐Ÿ‡ฒ๐Ÿ‡ฝ","๐Ÿ‡ซ๐Ÿ‡ฒ","๐Ÿ‡ฒ๐Ÿ‡ฉ","๐Ÿ‡ฒ๐Ÿ‡จ","๐Ÿ‡ฒ๐Ÿ‡ณ","๐Ÿ‡ฒ๐Ÿ‡ช","๐Ÿ‡ฒ๐Ÿ‡ธ","๐Ÿ‡ฒ๐Ÿ‡ฆ","๐Ÿ‡ฒ๐Ÿ‡ฟ","๐Ÿ‡ฒ๐Ÿ‡ฒ","๐Ÿ‡ณ๐Ÿ‡ฆ","๐Ÿ‡ณ๐Ÿ‡ท","๐Ÿ‡ณ๐Ÿ‡ต","๐Ÿ‡ณ๐Ÿ‡ฑ","๐Ÿ‡ณ๐Ÿ‡จ","๐Ÿ‡ณ๐Ÿ‡ฟ","๐Ÿ‡ณ๐Ÿ‡ฎ","๐Ÿ‡ณ๐Ÿ‡ช","๐Ÿ‡ณ๐Ÿ‡ฌ","๐Ÿ‡ณ๐Ÿ‡บ","๐Ÿ‡ณ๐Ÿ‡ซ","๐Ÿ‡ฐ๐Ÿ‡ต","๐Ÿ‡ฒ๐Ÿ‡ฐ","๐Ÿ‡ฒ๐Ÿ‡ต","๐Ÿ‡ณ๐Ÿ‡ด","๐Ÿ‡ด๐Ÿ‡ฒ","๐Ÿ‡ต๐Ÿ‡ฐ","๐Ÿ‡ต๐Ÿ‡ผ","๐Ÿ‡ต๐Ÿ‡ธ","๐Ÿ‡ต๐Ÿ‡ฆ","๐Ÿ‡ต๐Ÿ‡ฌ","๐Ÿ‡ต๐Ÿ‡พ","๐Ÿ‡ต๐Ÿ‡ช","๐Ÿ‡ต๐Ÿ‡ญ","๐Ÿ‡ต๐Ÿ‡ณ","๐Ÿ‡ต๐Ÿ‡ฑ","๐Ÿ‡ต๐Ÿ‡น","๐Ÿ‡ต๐Ÿ‡ท","๐Ÿ‡ถ๐Ÿ‡ฆ","๐Ÿ‡ท๐Ÿ‡ช","๐Ÿ‡ท๐Ÿ‡ด","๐Ÿ‡ท๐Ÿ‡บ","๐Ÿ‡ท๐Ÿ‡ผ","๐Ÿ‡ผ๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡ฒ","๐Ÿ‡ธ๐Ÿ‡น","๐Ÿ‡ธ๐Ÿ‡ฆ","๐Ÿ‡ธ๐Ÿ‡ณ","๐Ÿ‡ท๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡จ","๐Ÿ‡ธ๐Ÿ‡ฑ","๐Ÿ‡ธ๐Ÿ‡ฌ","๐Ÿ‡ธ๐Ÿ‡ฝ","๐Ÿ‡ธ๐Ÿ‡ฐ","๐Ÿ‡ธ๐Ÿ‡ฎ","๐Ÿ‡ฌ๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡ง","๐Ÿ‡ธ๐Ÿ‡ด","๐Ÿ‡ฟ๐Ÿ‡ฆ","๐Ÿ‡ฐ๐Ÿ‡ท","๐Ÿ‡ธ๐Ÿ‡ธ","๐Ÿ‡ช๐Ÿ‡ธ","๐Ÿ‡ฑ๐Ÿ‡ฐ","๐Ÿ‡ง๐Ÿ‡ฑ","๐Ÿ‡ธ๐Ÿ‡ญ","๐Ÿ‡ฐ๐Ÿ‡ณ","๐Ÿ‡ฑ๐Ÿ‡จ","๐Ÿ‡ต๐Ÿ‡ฒ","๐Ÿ‡ป๐Ÿ‡จ","๐Ÿ‡ธ๐Ÿ‡ฉ","๐Ÿ‡ธ๐Ÿ‡ท","๐Ÿ‡ธ๐Ÿ‡ช","๐Ÿ‡จ๐Ÿ‡ญ","๐Ÿ‡ธ๐Ÿ‡พ","๐Ÿ‡น๐Ÿ‡ผ","๐Ÿ‡น๐Ÿ‡ฏ","๐Ÿ‡น๐Ÿ‡ฟ","๐Ÿ‡น๐Ÿ‡ญ","๐Ÿ‡น๐Ÿ‡ฑ","๐Ÿ‡น๐Ÿ‡ฌ","๐Ÿ‡น๐Ÿ‡ฐ","๐Ÿ‡น๐Ÿ‡ด","๐Ÿ‡น๐Ÿ‡น","๐Ÿ‡น๐Ÿ‡ณ","๐Ÿ‡น๐Ÿ‡ท","๐Ÿ‡น๐Ÿ‡ฒ","๐Ÿ‡น๐Ÿ‡จ","๐Ÿ‡น๐Ÿ‡ป","๐Ÿ‡บ๐Ÿ‡ฌ","๐Ÿ‡บ๐Ÿ‡ฆ","๐Ÿ‡ฆ๐Ÿ‡ช","๐Ÿ‡ฌ๐Ÿ‡ง","๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ","๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ","๐Ÿด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ","๐Ÿ‡บ๐Ÿ‡ธ","๐Ÿ‡บ๐Ÿ‡พ","๐Ÿ‡ป๐Ÿ‡ฎ","๐Ÿ‡บ๐Ÿ‡ฟ","๐Ÿ‡ป๐Ÿ‡บ","๐Ÿ‡ป๐Ÿ‡ฆ","๐Ÿ‡ป๐Ÿ‡ช","๐Ÿ‡ป๐Ÿ‡ณ","๐Ÿ‡ผ๐Ÿ‡ซ","๐Ÿ‡ช๐Ÿ‡ญ","๐Ÿ‡พ๐Ÿ‡ช","๐Ÿ‡ฟ๐Ÿ‡ฒ","๐Ÿ‡ฟ๐Ÿ‡ผ" @@ -329,7 +342,8 @@ ========================================= -"๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿ˜…","๐Ÿ˜‚","๐Ÿคฃ","๐Ÿฅฒ","โ˜บ๏ธ","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿ™‚","๐Ÿ™ƒ","๐Ÿ˜‰","๐Ÿ˜Œ","๐Ÿ˜","๐Ÿฅฐ","๐Ÿ˜˜","๐Ÿ˜—","๐Ÿ˜™","๐Ÿ˜š","๐Ÿ˜‹","๐Ÿ˜›","๐Ÿ˜","๐Ÿ˜œ","๐Ÿคช","๐Ÿคจ","๐Ÿง","๐Ÿค“","๐Ÿ˜Ž","๐Ÿฅธ","๐Ÿคฉ","๐Ÿฅณ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ˜ž","๐Ÿ˜”","๐Ÿ˜Ÿ","๐Ÿ˜•","๐Ÿ™","โ˜น๏ธ","๐Ÿ˜ฃ","๐Ÿ˜–","๐Ÿ˜ซ","๐Ÿ˜ฉ","๐Ÿฅบ","๐Ÿ˜ข","๐Ÿ˜ญ","๐Ÿ˜ค","๐Ÿ˜ ","๐Ÿ˜ก","๐Ÿคฌ","๐Ÿคฏ","๐Ÿ˜ณ","๐Ÿฅต","๐Ÿฅถ","๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿ˜ฑ","๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜“","๐Ÿค—","๐Ÿค”","๐Ÿคญ","๐Ÿคซ","๐Ÿคฅ","๐Ÿ˜ถ","๐Ÿ˜","๐Ÿ˜‘","๐Ÿ˜ฌ","๐Ÿ™„","๐Ÿ˜ฏ","๐Ÿ˜ฆ","๐Ÿ˜ง","๐Ÿ˜ฎ","๐Ÿ˜ฒ","๐Ÿฅฑ","๐Ÿ˜ด","๐Ÿคค","๐Ÿ˜ช","๐Ÿ˜ฎโ€๐Ÿ’จ","๐Ÿ˜ต","๐Ÿ˜ตโ€๐Ÿ’ซ","๐Ÿค","๐Ÿฅด","๐Ÿคข","๐Ÿคฎ","๐Ÿคง","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿค‘","๐Ÿค ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ‘น","๐Ÿ‘บ","๐Ÿคก","๐Ÿ’ฉ","๐Ÿ‘ป","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ‘ฝ","๐Ÿ‘พ","๐Ÿค–","๐ŸŽƒ","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น","๐Ÿ˜ป","๐Ÿ˜ผ","๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ", +"๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿฅน","๐Ÿ˜…","๐Ÿ˜‚","๐Ÿคฃ","๐Ÿฅฒ","โ˜บ๏ธ","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿ™‚","๐Ÿ™ƒ","๐Ÿ˜‰","๐Ÿ˜Œ","๐Ÿ˜","๐Ÿฅฐ","๐Ÿ˜˜","๐Ÿ˜—","๐Ÿ˜™","๐Ÿ˜š","๐Ÿ˜‹","๐Ÿ˜›","๐Ÿ˜","๐Ÿ˜œ","๐Ÿคช","๐Ÿคจ","๐Ÿง","๐Ÿค“","๐Ÿ˜Ž","๐Ÿฅธ","๐Ÿคฉ","๐Ÿฅณ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ˜ž","๐Ÿ˜”","๐Ÿ˜Ÿ","๐Ÿ˜•","๐Ÿ™","โ˜น๏ธ","๐Ÿ˜ฃ","๐Ÿ˜–","๐Ÿ˜ซ","๐Ÿ˜ฉ","๐Ÿฅบ","๐Ÿ˜ข","๐Ÿ˜ญ","๐Ÿ˜ค","๐Ÿ˜ ","๐Ÿ˜ก","๐Ÿคฌ","๐Ÿคฏ","๐Ÿ˜ณ","๐Ÿฅต","๐Ÿฅถ","๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿ˜ฑ","๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜“","๐Ÿค—","๐Ÿค”","๐Ÿซฃ","๐Ÿคญ","๐Ÿซข","๐Ÿซก","๐Ÿคซ","๐Ÿซ ","๐Ÿคฅ","๐Ÿ˜ถ","๐Ÿซฅ","๐Ÿ˜","๐Ÿซค","๐Ÿ˜‘","๐Ÿซจ","๐Ÿ˜ฌ","๐Ÿ™„","๐Ÿ˜ฏ","๐Ÿ˜ฆ","๐Ÿ˜ง","๐Ÿ˜ฎ","๐Ÿ˜ฒ","๐Ÿฅฑ","๐Ÿ˜ด","๐Ÿคค","๐Ÿ˜ช","๐Ÿ˜ฎโ€๐Ÿ’จ","๐Ÿ˜ต","๐Ÿ˜ตโ€๐Ÿ’ซ","๐Ÿค","๐Ÿฅด","๐Ÿคข","๐Ÿคฎ","๐Ÿคง","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿค‘","๐Ÿค ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ‘น","๐Ÿ‘บ","๐Ÿคก","๐Ÿ’ฉ","๐Ÿ‘ป","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ‘ฝ","๐Ÿ‘พ","๐Ÿค–","๐ŸŽƒ","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น","๐Ÿ˜ป","๐Ÿ˜ผ","๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ", +"๐Ÿซถ", "๐Ÿคฒ", "๐Ÿ‘", "๐Ÿ™Œ", @@ -341,13 +355,18 @@ "โœŠ", "๐Ÿค›", "๐Ÿคœ", +"๐Ÿซท", +"๐Ÿซธ", "๐Ÿคž", "โœŒ๏ธ", +"๐Ÿซฐ", "๐ŸคŸ", "๐Ÿค˜", "๐Ÿ‘Œ", "๐ŸคŒ", "๐Ÿค", +"๐Ÿซณ", +"๐Ÿซด", "๐Ÿ‘ˆ", "๐Ÿ‘‰", "๐Ÿ‘†", @@ -359,14 +378,17 @@ "๐Ÿ––", "๐Ÿ‘‹", "๐Ÿค™", +"๐Ÿซฒ", +"๐Ÿซฑ", "๐Ÿ’ช", "๐Ÿฆพ", "๐Ÿ–•", "โœ๏ธ", "๐Ÿ™", +"๐Ÿซต", "๐Ÿฆถ", "๐Ÿฆต", -"๐Ÿฆฟ","๐Ÿ’„","๐Ÿ’‹","๐Ÿ‘„","๐Ÿฆท","๐Ÿ‘…", +"๐Ÿฆฟ","๐Ÿ’„","๐Ÿ’‹","๐Ÿ‘„","๐Ÿซฆ","๐Ÿฆท","๐Ÿ‘…", "๐Ÿ‘‚", "๐Ÿฆป", "๐Ÿ‘ƒ", @@ -471,6 +493,7 @@ "๐Ÿคต", "๐Ÿคตโ€โ™‚๏ธ", "๐Ÿ‘ธ", +"๐Ÿซ…", "๐Ÿคด", "๐Ÿฅท", "๐Ÿฆธโ€โ™€๏ธ", @@ -488,6 +511,7 @@ "๐Ÿงโ€โ™€๏ธ", "๐Ÿง", "๐Ÿงโ€โ™‚๏ธ", +"๐ŸงŒ", "๐Ÿง›โ€โ™€๏ธ", "๐Ÿง›", "๐Ÿง›โ€โ™‚๏ธ", @@ -500,6 +524,8 @@ "๐Ÿงšโ€โ™‚๏ธ", "๐Ÿ‘ผ", "๐Ÿคฐ", +"๐Ÿซ„", +"๐Ÿซƒ", "๐Ÿคฑ", "๐Ÿ‘ฉโ€๐Ÿผ", "๐Ÿง‘โ€๐Ÿผ", @@ -631,24 +657,24 @@ "๐Ÿคนโ€โ™€๏ธ", "๐Ÿคน", "๐Ÿคนโ€โ™‚๏ธ", -"๐ŸŽญ","๐Ÿฉฐ","๐ŸŽจ","๐ŸŽฌ","๐ŸŽค","๐ŸŽง","๐ŸŽผ","๐ŸŽน","๐Ÿฅ","๐Ÿช˜","๐ŸŽท","๐ŸŽบ","๐Ÿช—","๐ŸŽธ","๐Ÿช•","๐ŸŽป","๐ŸŽฒ","โ™Ÿ","๐ŸŽฏ","๐ŸŽณ","๐ŸŽฎ","๐ŸŽฐ","๐Ÿงฉ" +"๐ŸŽญ","๐Ÿฉฐ","๐ŸŽจ","๐ŸŽฌ","๐ŸŽค","๐ŸŽง","๐ŸŽผ","๐ŸŽน","๐Ÿช‡","๐Ÿฅ","๐Ÿช˜","๐ŸŽท","๐ŸŽบ","๐Ÿช—","๐ŸŽธ","๐Ÿช•","๐ŸŽป","๐Ÿชˆ","๐ŸŽฒ","โ™Ÿ","๐ŸŽฏ","๐ŸŽณ","๐ŸŽฎ","๐ŸŽฐ","๐Ÿงฉ" -"โŒš๏ธ","๐Ÿ“ฑ","๐Ÿ“ฒ","๐Ÿ’ป","โŒจ๏ธ","๐Ÿ–ฅ","๐Ÿ–จ","๐Ÿ–ฑ","๐Ÿ–ฒ","๐Ÿ•น","๐Ÿ—œ","๐Ÿ’ฝ","๐Ÿ’พ","๐Ÿ’ฟ","๐Ÿ“€","๐Ÿ“ผ","๐Ÿ“ท","๐Ÿ“ธ","๐Ÿ“น","๐ŸŽฅ","๐Ÿ“ฝ","๐ŸŽž","๐Ÿ“ž","โ˜Ž๏ธ","๐Ÿ“Ÿ","๐Ÿ“ ","๐Ÿ“บ","๐Ÿ“ป","๐ŸŽ™","๐ŸŽš","๐ŸŽ›","๐Ÿงญ","โฑ","โฒ","โฐ","๐Ÿ•ฐ","โŒ›๏ธ","โณ","๐Ÿ“ก","๐Ÿ”‹","๐Ÿ”Œ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ•ฏ","๐Ÿช”","๐Ÿงฏ","๐Ÿ›ข","๐Ÿ’ธ","๐Ÿ’ต","๐Ÿ’ด","๐Ÿ’ถ","๐Ÿ’ท","๐Ÿช™","๐Ÿ’ฐ","๐Ÿ’ณ","๐Ÿ’Ž","โš–๏ธ","๐Ÿชœ","๐Ÿงฐ","๐Ÿช›","๐Ÿ”ง","๐Ÿ”จ","โš’","๐Ÿ› ","โ›","๐Ÿชš","๐Ÿ”ฉ","โš™๏ธ","๐Ÿชค","๐Ÿงฑ","โ›“","๐Ÿงฒ","๐Ÿ”ซ","๐Ÿ’ฃ","๐Ÿงจ","๐Ÿช“","๐Ÿ”ช","๐Ÿ—ก","โš”๏ธ","๐Ÿ›ก","๐Ÿšฌ","โšฐ๏ธ","๐Ÿชฆ","โšฑ๏ธ","๐Ÿบ","๐Ÿ”ฎ","๐Ÿ“ฟ","๐Ÿงฟ","๐Ÿ’ˆ","โš—๏ธ","๐Ÿ”ญ","๐Ÿ”ฌ","๐Ÿ•ณ","๐Ÿฉน","๐Ÿฉบ","๐Ÿ’Š","๐Ÿ’‰","๐Ÿฉธ","๐Ÿงฌ","๐Ÿฆ ","๐Ÿงซ","๐Ÿงช","๐ŸŒก","๐Ÿงน","๐Ÿช ","๐Ÿงบ","๐Ÿงป","๐Ÿšฝ","๐Ÿšฐ","๐Ÿšฟ","๐Ÿ›", +"โŒš๏ธ","๐Ÿ“ฑ","๐Ÿ“ฒ","๐Ÿ’ป","โŒจ๏ธ","๐Ÿ–ฅ","๐Ÿ–จ","๐Ÿ–ฑ","๐Ÿ–ฒ","๐Ÿ•น","๐Ÿ—œ","๐Ÿ’ฝ","๐Ÿ’พ","๐Ÿ’ฟ","๐Ÿ“€","๐Ÿ“ผ","๐Ÿ“ท","๐Ÿ“ธ","๐Ÿ“น","๐ŸŽฅ","๐Ÿ“ฝ","๐ŸŽž","๐Ÿ“ž","โ˜Ž๏ธ","๐Ÿ“Ÿ","๐Ÿ“ ","๐Ÿ“บ","๐Ÿ“ป","๐ŸŽ™","๐ŸŽš","๐ŸŽ›","๐Ÿงญ","โฑ","โฒ","โฐ","๐Ÿ•ฐ","โŒ›๏ธ","โณ","๐Ÿ“ก","๐Ÿ”‹","๐Ÿชซ","๐Ÿ”Œ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ•ฏ","๐Ÿช”","๐Ÿงฏ","๐Ÿ›ข","๐Ÿ’ธ","๐Ÿ’ต","๐Ÿ’ด","๐Ÿ’ถ","๐Ÿ’ท","๐Ÿช™","๐Ÿ’ฐ","๐Ÿ’ณ","๐Ÿชช","๐Ÿ’Ž","โš–๏ธ","๐Ÿชœ","๐Ÿงฐ","๐Ÿช›","๐Ÿ”ง","๐Ÿ”จ","โš’","๐Ÿ› ","โ›","๐Ÿชš","๐Ÿ”ฉ","โš™๏ธ","๐Ÿชค","๐Ÿงฑ","โ›“","๐Ÿงฒ","๐Ÿ”ซ","๐Ÿ’ฃ","๐Ÿงจ","๐Ÿช“","๐Ÿ”ช","๐Ÿ—ก","โš”๏ธ","๐Ÿ›ก","๐Ÿšฌ","โšฐ๏ธ","๐Ÿชฆ","โšฑ๏ธ","๐Ÿบ","๐Ÿ”ฎ","๐Ÿ“ฟ","๐Ÿงฟ","๐Ÿชฌ","๐Ÿ’ˆ","โš—๏ธ","๐Ÿ”ญ","๐Ÿ”ฌ","๐Ÿ•ณ","๐Ÿฉป","๐Ÿฉน","๐Ÿฉบ","๐Ÿ’Š","๐Ÿ’‰","๐Ÿฉธ","๐Ÿงฌ","๐Ÿฆ ","๐Ÿงซ","๐Ÿงช","๐ŸŒก","๐Ÿงน","๐Ÿช ","๐Ÿงบ","๐Ÿงป","๐Ÿšฝ","๐Ÿšฐ","๐Ÿšฟ","๐Ÿ›", "๐Ÿ›€", -"๐Ÿงผ","๐Ÿชฅ","๐Ÿช’","๐Ÿงฝ","๐Ÿชฃ","๐Ÿงด","๐Ÿ›Ž","๐Ÿ”‘","๐Ÿ—","๐Ÿšช","๐Ÿช‘","๐Ÿ›‹","๐Ÿ›","๐Ÿ›Œ","๐Ÿงธ","๐Ÿช†","๐Ÿ–ผ","๐Ÿชž","๐ŸชŸ","๐Ÿ›","๐Ÿ›’","๐ŸŽ","๐ŸŽˆ","๐ŸŽ","๐ŸŽ€","๐Ÿช„","๐Ÿช…","๐ŸŽŠ","๐ŸŽ‰","๐ŸŽŽ","๐Ÿฎ","๐ŸŽ","๐Ÿงง","โœ‰๏ธ","๐Ÿ“ฉ","๐Ÿ“จ","๐Ÿ“ง","๐Ÿ’Œ","๐Ÿ“ฅ","๐Ÿ“ค","๐Ÿ“ฆ","๐Ÿท","๐Ÿชง","๐Ÿ“ช","๐Ÿ“ซ","๐Ÿ“ฌ","๐Ÿ“ญ","๐Ÿ“ฎ","๐Ÿ“ฏ","๐Ÿ“œ","๐Ÿ“ƒ","๐Ÿ“„","๐Ÿ“‘","๐Ÿงพ","๐Ÿ“Š","๐Ÿ“ˆ","๐Ÿ“‰","๐Ÿ—’","๐Ÿ—“","๐Ÿ“†","๐Ÿ“…","๐Ÿ—‘","๐Ÿ“‡","๐Ÿ—ƒ","๐Ÿ—ณ","๐Ÿ—„","๐Ÿ“‹","๐Ÿ“","๐Ÿ“‚","๐Ÿ—‚","๐Ÿ—ž","๐Ÿ“ฐ","๐Ÿ““","๐Ÿ“”","๐Ÿ“’","๐Ÿ“•","๐Ÿ“—","๐Ÿ“˜","๐Ÿ“™","๐Ÿ“š","๐Ÿ“–","๐Ÿ”–","๐Ÿงท","๐Ÿ”—","๐Ÿ“Ž","๐Ÿ–‡","๐Ÿ“","๐Ÿ“","๐Ÿงฎ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ–Š","๐Ÿ–‹","โœ’๏ธ","๐Ÿ–Œ","๐Ÿ–","๐Ÿ“","โœ๏ธ","๐Ÿ”","๐Ÿ”Ž","๐Ÿ”","๐Ÿ”","๐Ÿ”’","๐Ÿ”“" +"๐Ÿงผ","๐Ÿชฅ","๐Ÿช’","๐Ÿชฎ","๐Ÿงฝ","๐Ÿชฃ","๐Ÿงด","๐Ÿ›Ž","๐Ÿ”‘","๐Ÿ—","๐Ÿšช","๐Ÿช‘","๐Ÿ›‹","๐Ÿ›","๐Ÿ›Œ","๐Ÿงธ","๐Ÿช†","๐Ÿ–ผ","๐Ÿชž","๐ŸชŸ","๐Ÿ›","๐Ÿ›’","๐ŸŽ","๐ŸŽˆ","๐ŸŽ","๐ŸŽ€","๐Ÿช„","๐Ÿช…","๐ŸŽŠ","๐ŸŽ‰","๐ŸŽŽ","๐Ÿชญ","๐Ÿฎ","๐ŸŽ","๐Ÿชฉ","๐Ÿงง","โœ‰๏ธ","๐Ÿ“ฉ","๐Ÿ“จ","๐Ÿ“ง","๐Ÿ’Œ","๐Ÿ“ฅ","๐Ÿ“ค","๐Ÿ“ฆ","๐Ÿท","๐Ÿชง","๐Ÿ“ช","๐Ÿ“ซ","๐Ÿ“ฌ","๐Ÿ“ญ","๐Ÿ“ฎ","๐Ÿ“ฏ","๐Ÿ“œ","๐Ÿ“ƒ","๐Ÿ“„","๐Ÿ“‘","๐Ÿงพ","๐Ÿ“Š","๐Ÿ“ˆ","๐Ÿ“‰","๐Ÿ—’","๐Ÿ—“","๐Ÿ“†","๐Ÿ“…","๐Ÿ—‘","๐Ÿ“‡","๐Ÿ—ƒ","๐Ÿ—ณ","๐Ÿ—„","๐Ÿ“‹","๐Ÿ“","๐Ÿ“‚","๐Ÿ—‚","๐Ÿ—ž","๐Ÿ“ฐ","๐Ÿ““","๐Ÿ“”","๐Ÿ“’","๐Ÿ“•","๐Ÿ“—","๐Ÿ“˜","๐Ÿ“™","๐Ÿ“š","๐Ÿ“–","๐Ÿ”–","๐Ÿงท","๐Ÿ”—","๐Ÿ“Ž","๐Ÿ–‡","๐Ÿ“","๐Ÿ“","๐Ÿงฎ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ–Š","๐Ÿ–‹","โœ’๏ธ","๐Ÿ–Œ","๐Ÿ–","๐Ÿ“","โœ๏ธ","๐Ÿ”","๐Ÿ”Ž","๐Ÿ”","๐Ÿ”","๐Ÿ”’","๐Ÿ”“" ========================================= -"๐Ÿคฒ","๐Ÿ‘","๐Ÿ™Œ","๐Ÿ‘","๐Ÿ‘","๐Ÿ‘Ž","๐Ÿ‘Š","โœŠ","๐Ÿค›","๐Ÿคœ","๐Ÿคž","โœŒ๏ธ","๐ŸคŸ","๐Ÿค˜","๐Ÿ‘Œ","๐ŸคŒ","๐Ÿค","๐Ÿ‘ˆ","๐Ÿ‘‰","๐Ÿ‘†","๐Ÿ‘‡","โ˜๏ธ","โœ‹","๐Ÿคš","๐Ÿ–","๐Ÿ––","๐Ÿ‘‹","๐Ÿค™","๐Ÿ’ช","๐Ÿ–•","โœ๏ธ","๐Ÿ™","๐Ÿฆถ","๐Ÿฆต","๐Ÿ‘‚","๐Ÿฆป","๐Ÿ‘ƒ","๐Ÿ‘ถ","๐Ÿ‘ง","๐Ÿง’","๐Ÿ‘ฆ","๐Ÿ‘ฉ","๐Ÿง‘","๐Ÿ‘จ","๐Ÿ‘ฉโ€๐Ÿฆฑ","๐Ÿง‘โ€๐Ÿฆฑ","๐Ÿ‘จโ€๐Ÿฆฑ","๐Ÿ‘ฉโ€๐Ÿฆฐ","๐Ÿง‘โ€๐Ÿฆฐ","๐Ÿ‘จโ€๐Ÿฆฐ","๐Ÿ‘ฑโ€โ™€๏ธ","๐Ÿ‘ฑ","๐Ÿ‘ฑโ€โ™‚๏ธ","๐Ÿ‘ฉโ€๐Ÿฆณ","๐Ÿง‘โ€๐Ÿฆณ","๐Ÿ‘จโ€๐Ÿฆณ","๐Ÿ‘ฉโ€๐Ÿฆฒ","๐Ÿง‘โ€๐Ÿฆฒ","๐Ÿ‘จโ€๐Ÿฆฒ","๐Ÿง”โ€โ™€๏ธ","๐Ÿง”","๐Ÿง”โ€โ™‚๏ธ","๐Ÿ‘ต","๐Ÿง“","๐Ÿ‘ด","๐Ÿ‘ฒ","๐Ÿ‘ณโ€โ™€๏ธ","๐Ÿ‘ณ","๐Ÿ‘ณโ€โ™‚๏ธ","๐Ÿง•","๐Ÿ‘ฎโ€โ™€๏ธ","๐Ÿ‘ฎ","๐Ÿ‘ฎโ€โ™‚๏ธ","๐Ÿ‘ทโ€โ™€๏ธ","๐Ÿ‘ท","๐Ÿ‘ทโ€โ™‚๏ธ","๐Ÿ’‚โ€โ™€๏ธ","๐Ÿ’‚","๐Ÿ’‚โ€โ™‚๏ธ","๐Ÿ•ต๏ธโ€โ™€๏ธ","๐Ÿ•ต๏ธ","๐Ÿ•ต๏ธโ€โ™‚๏ธ","๐Ÿ‘ฉโ€โš•๏ธ","๐Ÿง‘โ€โš•๏ธ","๐Ÿ‘จโ€โš•๏ธ","๐Ÿ‘ฉโ€๐ŸŒพ","๐Ÿง‘โ€๐ŸŒพ","๐Ÿ‘จโ€๐ŸŒพ","๐Ÿ‘ฉโ€๐Ÿณ","๐Ÿง‘โ€๐Ÿณ","๐Ÿ‘จโ€๐Ÿณ","๐Ÿ‘ฉโ€๐ŸŽ“","๐Ÿง‘โ€๐ŸŽ“","๐Ÿ‘จโ€๐ŸŽ“","๐Ÿ‘ฉโ€๐ŸŽค","๐Ÿง‘โ€๐ŸŽค","๐Ÿ‘จโ€๐ŸŽค","๐Ÿ‘ฉโ€๐Ÿซ","๐Ÿง‘โ€๐Ÿซ","๐Ÿ‘จโ€๐Ÿซ","๐Ÿ‘ฉโ€๐Ÿญ","๐Ÿง‘โ€๐Ÿญ","๐Ÿ‘จโ€๐Ÿญ","๐Ÿ‘ฉโ€๐Ÿ’ป","๐Ÿง‘โ€๐Ÿ’ป","๐Ÿ‘จโ€๐Ÿ’ป","๐Ÿ‘ฉโ€๐Ÿ’ผ","๐Ÿง‘โ€๐Ÿ’ผ","๐Ÿ‘จโ€๐Ÿ’ผ","๐Ÿ‘ฉโ€๐Ÿ”ง","๐Ÿง‘โ€๐Ÿ”ง","๐Ÿ‘จโ€๐Ÿ”ง","๐Ÿ‘ฉโ€๐Ÿ”ฌ","๐Ÿง‘โ€๐Ÿ”ฌ","๐Ÿ‘จโ€๐Ÿ”ฌ","๐Ÿ‘ฉโ€๐ŸŽจ","๐Ÿง‘โ€๐ŸŽจ","๐Ÿ‘จโ€๐ŸŽจ","๐Ÿ‘ฉโ€๐Ÿš’","๐Ÿง‘โ€๐Ÿš’","๐Ÿ‘จโ€๐Ÿš’","๐Ÿ‘ฉโ€โœˆ๏ธ","๐Ÿง‘โ€โœˆ๏ธ","๐Ÿ‘จโ€โœˆ๏ธ","๐Ÿ‘ฉโ€๐Ÿš€","๐Ÿง‘โ€๐Ÿš€","๐Ÿ‘จโ€๐Ÿš€","๐Ÿ‘ฉโ€โš–๏ธ","๐Ÿง‘โ€โš–๏ธ","๐Ÿ‘จโ€โš–๏ธ","๐Ÿ‘ฐโ€โ™€๏ธ","๐Ÿ‘ฐ","๐Ÿ‘ฐโ€โ™‚๏ธ","๐Ÿคตโ€โ™€๏ธ","๐Ÿคต","๐Ÿคตโ€โ™‚๏ธ","๐Ÿ‘ธ","๐Ÿคด","๐Ÿฅท","๐Ÿฆธโ€โ™€๏ธ","๐Ÿฆธ","๐Ÿฆธโ€โ™‚๏ธ","๐Ÿฆนโ€โ™€๏ธ","๐Ÿฆน","๐Ÿฆนโ€โ™‚๏ธ","๐Ÿคถ","๐Ÿง‘โ€๐ŸŽ„","๐ŸŽ…","๐Ÿง™โ€โ™€๏ธ","๐Ÿง™","๐Ÿง™โ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿง›โ€โ™€๏ธ","๐Ÿง›","๐Ÿง›โ€โ™‚๏ธ","๐Ÿงœโ€โ™€๏ธ","๐Ÿงœ","๐Ÿงœโ€โ™‚๏ธ","๐Ÿงšโ€โ™€๏ธ","๐Ÿงš","๐Ÿงšโ€โ™‚๏ธ","๐Ÿ‘ผ","๐Ÿคฐ","๐Ÿคฑ","๐Ÿ‘ฉโ€๐Ÿผ","๐Ÿง‘โ€๐Ÿผ","๐Ÿ‘จโ€๐Ÿผ","๐Ÿ™‡โ€โ™€๏ธ","๐Ÿ™‡","๐Ÿ™‡โ€โ™‚๏ธ","๐Ÿ’โ€โ™€๏ธ","๐Ÿ’","๐Ÿ’โ€โ™‚๏ธ","๐Ÿ™…โ€โ™€๏ธ","๐Ÿ™…","๐Ÿ™…โ€โ™‚๏ธ","๐Ÿ™†โ€โ™€๏ธ","๐Ÿ™†","๐Ÿ™†โ€โ™‚๏ธ","๐Ÿ™‹โ€โ™€๏ธ","๐Ÿ™‹","๐Ÿ™‹โ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿคฆโ€โ™€๏ธ","๐Ÿคฆ","๐Ÿคฆโ€โ™‚๏ธ","๐Ÿคทโ€โ™€๏ธ","๐Ÿคท","๐Ÿคทโ€โ™‚๏ธ","๐Ÿ™Žโ€โ™€๏ธ","๐Ÿ™Ž","๐Ÿ™Žโ€โ™‚๏ธ","๐Ÿ™โ€โ™€๏ธ","๐Ÿ™","๐Ÿ™โ€โ™‚๏ธ","๐Ÿ’‡โ€โ™€๏ธ","๐Ÿ’‡","๐Ÿ’‡โ€โ™‚๏ธ","๐Ÿ’†โ€โ™€๏ธ","๐Ÿ’†","๐Ÿ’†โ€โ™‚๏ธ","๐Ÿง–โ€โ™€๏ธ","๐Ÿง–","๐Ÿง–โ€โ™‚๏ธ","๐Ÿ’…","๐Ÿคณ","๐Ÿ’ƒ","๐Ÿ•บ","๐Ÿ•ด","๐Ÿ‘ฉโ€๐Ÿฆฝ","๐Ÿง‘โ€๐Ÿฆฝ","๐Ÿ‘จโ€๐Ÿฆฝ","๐Ÿ‘ฉโ€๐Ÿฆผ","๐Ÿง‘โ€๐Ÿฆผ","๐Ÿ‘จโ€๐Ÿฆผ","๐Ÿšถโ€โ™€๏ธ","๐Ÿšถ","๐Ÿšถโ€โ™‚๏ธ","๐Ÿ‘ฉโ€๐Ÿฆฏ","๐Ÿง‘โ€๐Ÿฆฏ","๐Ÿ‘จโ€๐Ÿฆฏ","๐ŸงŽโ€โ™€๏ธ","๐ŸงŽ","๐ŸงŽโ€โ™‚๏ธ","๐Ÿƒโ€โ™€๏ธ","๐Ÿƒ","๐Ÿƒโ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿ‹๏ธโ€โ™€๏ธ","๐Ÿ‹๏ธ","๐Ÿ‹๏ธโ€โ™‚๏ธ","๐Ÿคธโ€โ™€๏ธ","๐Ÿคธ","๐Ÿคธโ€โ™‚๏ธ","โ›น๏ธโ€โ™€๏ธ","โ›น๏ธ","โ›น๏ธโ€โ™‚๏ธ","๐Ÿคพโ€โ™€๏ธ","๐Ÿคพ","๐Ÿคพโ€โ™‚๏ธ","๐ŸŒ๏ธโ€โ™€๏ธ","๐ŸŒ๏ธ","๐ŸŒ๏ธโ€โ™‚๏ธ","๐Ÿ‡","๐Ÿง˜โ€โ™€๏ธ","๐Ÿง˜","๐Ÿง˜โ€โ™‚๏ธ","๐Ÿ„โ€โ™€๏ธ","๐Ÿ„","๐Ÿ„โ€โ™‚๏ธ","๐ŸŠโ€โ™€๏ธ","๐ŸŠ","๐ŸŠโ€โ™‚๏ธ","๐Ÿคฝโ€โ™€๏ธ","๐Ÿคฝ","๐Ÿคฝโ€โ™‚๏ธ","๐Ÿšฃโ€โ™€๏ธ","๐Ÿšฃ","๐Ÿšฃโ€โ™‚๏ธ","๐Ÿง—โ€โ™€๏ธ","๐Ÿง—","๐Ÿง—โ€โ™‚๏ธ","๐Ÿšตโ€โ™€๏ธ","๐Ÿšต","๐Ÿšตโ€โ™‚๏ธ","๐Ÿšดโ€โ™€๏ธ","๐Ÿšด","๐Ÿšดโ€โ™‚๏ธ","๐Ÿคนโ€โ™€๏ธ","๐Ÿคน","๐Ÿคนโ€โ™‚๏ธ","๐Ÿ›€" +"๐Ÿซถ","๐Ÿคฒ","๐Ÿ‘","๐Ÿ™Œ","๐Ÿ‘","๐Ÿ‘","๐Ÿ‘Ž","๐Ÿ‘Š","โœŠ","๐Ÿค›","๐Ÿคœ","๐Ÿซท","๐Ÿซธ","๐Ÿคž","โœŒ๏ธ","๐Ÿซฐ","๐ŸคŸ","๐Ÿค˜","๐Ÿ‘Œ","๐ŸคŒ","๐Ÿค","๐Ÿซณ","๐Ÿซด","๐Ÿ‘ˆ","๐Ÿ‘‰","๐Ÿ‘†","๐Ÿ‘‡","โ˜๏ธ","โœ‹","๐Ÿคš","๐Ÿ–","๐Ÿ––","๐Ÿ‘‹","๐Ÿค™","๐Ÿซฒ","๐Ÿซฑ","๐Ÿ’ช","๐Ÿ–•","โœ๏ธ","๐Ÿ™","๐Ÿซต","๐Ÿฆถ","๐Ÿฆต","๐Ÿ‘‚","๐Ÿฆป","๐Ÿ‘ƒ","๐Ÿ‘ถ","๐Ÿ‘ง","๐Ÿง’","๐Ÿ‘ฆ","๐Ÿ‘ฉ","๐Ÿง‘","๐Ÿ‘จ","๐Ÿ‘ฉโ€๐Ÿฆฑ","๐Ÿง‘โ€๐Ÿฆฑ","๐Ÿ‘จโ€๐Ÿฆฑ","๐Ÿ‘ฉโ€๐Ÿฆฐ","๐Ÿง‘โ€๐Ÿฆฐ","๐Ÿ‘จโ€๐Ÿฆฐ","๐Ÿ‘ฑโ€โ™€๏ธ","๐Ÿ‘ฑ","๐Ÿ‘ฑโ€โ™‚๏ธ","๐Ÿ‘ฉโ€๐Ÿฆณ","๐Ÿง‘โ€๐Ÿฆณ","๐Ÿ‘จโ€๐Ÿฆณ","๐Ÿ‘ฉโ€๐Ÿฆฒ","๐Ÿง‘โ€๐Ÿฆฒ","๐Ÿ‘จโ€๐Ÿฆฒ","๐Ÿง”โ€โ™€๏ธ","๐Ÿง”","๐Ÿง”โ€โ™‚๏ธ","๐Ÿ‘ต","๐Ÿง“","๐Ÿ‘ด","๐Ÿ‘ฒ","๐Ÿ‘ณโ€โ™€๏ธ","๐Ÿ‘ณ","๐Ÿ‘ณโ€โ™‚๏ธ","๐Ÿง•","๐Ÿ‘ฎโ€โ™€๏ธ","๐Ÿ‘ฎ","๐Ÿ‘ฎโ€โ™‚๏ธ","๐Ÿ‘ทโ€โ™€๏ธ","๐Ÿ‘ท","๐Ÿ‘ทโ€โ™‚๏ธ","๐Ÿ’‚โ€โ™€๏ธ","๐Ÿ’‚","๐Ÿ’‚โ€โ™‚๏ธ","๐Ÿ•ต๏ธโ€โ™€๏ธ","๐Ÿ•ต๏ธ","๐Ÿ•ต๏ธโ€โ™‚๏ธ","๐Ÿ‘ฉโ€โš•๏ธ","๐Ÿง‘โ€โš•๏ธ","๐Ÿ‘จโ€โš•๏ธ","๐Ÿ‘ฉโ€๐ŸŒพ","๐Ÿง‘โ€๐ŸŒพ","๐Ÿ‘จโ€๐ŸŒพ","๐Ÿ‘ฉโ€๐Ÿณ","๐Ÿง‘โ€๐Ÿณ","๐Ÿ‘จโ€๐Ÿณ","๐Ÿ‘ฉโ€๐ŸŽ“","๐Ÿง‘โ€๐ŸŽ“","๐Ÿ‘จโ€๐ŸŽ“","๐Ÿ‘ฉโ€๐ŸŽค","๐Ÿง‘โ€๐ŸŽค","๐Ÿ‘จโ€๐ŸŽค","๐Ÿ‘ฉโ€๐Ÿซ","๐Ÿง‘โ€๐Ÿซ","๐Ÿ‘จโ€๐Ÿซ","๐Ÿ‘ฉโ€๐Ÿญ","๐Ÿง‘โ€๐Ÿญ","๐Ÿ‘จโ€๐Ÿญ","๐Ÿ‘ฉโ€๐Ÿ’ป","๐Ÿง‘โ€๐Ÿ’ป","๐Ÿ‘จโ€๐Ÿ’ป","๐Ÿ‘ฉโ€๐Ÿ’ผ","๐Ÿง‘โ€๐Ÿ’ผ","๐Ÿ‘จโ€๐Ÿ’ผ","๐Ÿ‘ฉโ€๐Ÿ”ง","๐Ÿง‘โ€๐Ÿ”ง","๐Ÿ‘จโ€๐Ÿ”ง","๐Ÿ‘ฉโ€๐Ÿ”ฌ","๐Ÿง‘โ€๐Ÿ”ฌ","๐Ÿ‘จโ€๐Ÿ”ฌ","๐Ÿ‘ฉโ€๐ŸŽจ","๐Ÿง‘โ€๐ŸŽจ","๐Ÿ‘จโ€๐ŸŽจ","๐Ÿ‘ฉโ€๐Ÿš’","๐Ÿง‘โ€๐Ÿš’","๐Ÿ‘จโ€๐Ÿš’","๐Ÿ‘ฉโ€โœˆ๏ธ","๐Ÿง‘โ€โœˆ๏ธ","๐Ÿ‘จโ€โœˆ๏ธ","๐Ÿ‘ฉโ€๐Ÿš€","๐Ÿง‘โ€๐Ÿš€","๐Ÿ‘จโ€๐Ÿš€","๐Ÿ‘ฉโ€โš–๏ธ","๐Ÿง‘โ€โš–๏ธ","๐Ÿ‘จโ€โš–๏ธ","๐Ÿ‘ฐโ€โ™€๏ธ","๐Ÿ‘ฐ","๐Ÿ‘ฐโ€โ™‚๏ธ","๐Ÿคตโ€โ™€๏ธ","๐Ÿคต","๐Ÿคตโ€โ™‚๏ธ","๐Ÿ‘ธ","๐Ÿซ…","๐Ÿคด","๐Ÿฅท","๐Ÿฆธโ€โ™€๏ธ","๐Ÿฆธ","๐Ÿฆธโ€โ™‚๏ธ","๐Ÿฆนโ€โ™€๏ธ","๐Ÿฆน","๐Ÿฆนโ€โ™‚๏ธ","๐Ÿคถ","๐Ÿง‘โ€๐ŸŽ„","๐ŸŽ…","๐Ÿง™โ€โ™€๏ธ","๐Ÿง™","๐Ÿง™โ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿง›โ€โ™€๏ธ","๐Ÿง›","๐Ÿง›โ€โ™‚๏ธ","๐Ÿงœโ€โ™€๏ธ","๐Ÿงœ","๐Ÿงœโ€โ™‚๏ธ","๐Ÿงšโ€โ™€๏ธ","๐Ÿงš","๐Ÿงšโ€โ™‚๏ธ","๐Ÿ‘ผ","๐Ÿคฐ","๐Ÿซ„","๐Ÿซƒ","๐Ÿคฑ","๐Ÿ‘ฉโ€๐Ÿผ","๐Ÿง‘โ€๐Ÿผ","๐Ÿ‘จโ€๐Ÿผ","๐Ÿ™‡โ€โ™€๏ธ","๐Ÿ™‡","๐Ÿ™‡โ€โ™‚๏ธ","๐Ÿ’โ€โ™€๏ธ","๐Ÿ’","๐Ÿ’โ€โ™‚๏ธ","๐Ÿ™…โ€โ™€๏ธ","๐Ÿ™…","๐Ÿ™…โ€โ™‚๏ธ","๐Ÿ™†โ€โ™€๏ธ","๐Ÿ™†","๐Ÿ™†โ€โ™‚๏ธ","๐Ÿ™‹โ€โ™€๏ธ","๐Ÿ™‹","๐Ÿ™‹โ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿคฆโ€โ™€๏ธ","๐Ÿคฆ","๐Ÿคฆโ€โ™‚๏ธ","๐Ÿคทโ€โ™€๏ธ","๐Ÿคท","๐Ÿคทโ€โ™‚๏ธ","๐Ÿ™Žโ€โ™€๏ธ","๐Ÿ™Ž","๐Ÿ™Žโ€โ™‚๏ธ","๐Ÿ™โ€โ™€๏ธ","๐Ÿ™","๐Ÿ™โ€โ™‚๏ธ","๐Ÿ’‡โ€โ™€๏ธ","๐Ÿ’‡","๐Ÿ’‡โ€โ™‚๏ธ","๐Ÿ’†โ€โ™€๏ธ","๐Ÿ’†","๐Ÿ’†โ€โ™‚๏ธ","๐Ÿง–โ€โ™€๏ธ","๐Ÿง–","๐Ÿง–โ€โ™‚๏ธ","๐Ÿ’…","๐Ÿคณ","๐Ÿ’ƒ","๐Ÿ•บ","๐Ÿ•ด","๐Ÿ‘ฉโ€๐Ÿฆฝ","๐Ÿง‘โ€๐Ÿฆฝ","๐Ÿ‘จโ€๐Ÿฆฝ","๐Ÿ‘ฉโ€๐Ÿฆผ","๐Ÿง‘โ€๐Ÿฆผ","๐Ÿ‘จโ€๐Ÿฆผ","๐Ÿšถโ€โ™€๏ธ","๐Ÿšถ","๐Ÿšถโ€โ™‚๏ธ","๐Ÿ‘ฉโ€๐Ÿฆฏ","๐Ÿง‘โ€๐Ÿฆฏ","๐Ÿ‘จโ€๐Ÿฆฏ","๐ŸงŽโ€โ™€๏ธ","๐ŸงŽ","๐ŸงŽโ€โ™‚๏ธ","๐Ÿƒโ€โ™€๏ธ","๐Ÿƒ","๐Ÿƒโ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿ‹๏ธโ€โ™€๏ธ","๐Ÿ‹๏ธ","๐Ÿ‹๏ธโ€โ™‚๏ธ","๐Ÿคธโ€โ™€๏ธ","๐Ÿคธ","๐Ÿคธโ€โ™‚๏ธ","โ›น๏ธโ€โ™€๏ธ","โ›น๏ธ","โ›น๏ธโ€โ™‚๏ธ","๐Ÿคพโ€โ™€๏ธ","๐Ÿคพ","๐Ÿคพโ€โ™‚๏ธ","๐ŸŒ๏ธโ€โ™€๏ธ","๐ŸŒ๏ธ","๐ŸŒ๏ธโ€โ™‚๏ธ","๐Ÿ‡","๐Ÿง˜โ€โ™€๏ธ","๐Ÿง˜","๐Ÿง˜โ€โ™‚๏ธ","๐Ÿ„โ€โ™€๏ธ","๐Ÿ„","๐Ÿ„โ€โ™‚๏ธ","๐ŸŠโ€โ™€๏ธ","๐ŸŠ","๐ŸŠโ€โ™‚๏ธ","๐Ÿคฝโ€โ™€๏ธ","๐Ÿคฝ","๐Ÿคฝโ€โ™‚๏ธ","๐Ÿšฃโ€โ™€๏ธ","๐Ÿšฃ","๐Ÿšฃโ€โ™‚๏ธ","๐Ÿง—โ€โ™€๏ธ","๐Ÿง—","๐Ÿง—โ€โ™‚๏ธ","๐Ÿšตโ€โ™€๏ธ","๐Ÿšต","๐Ÿšตโ€โ™‚๏ธ","๐Ÿšดโ€โ™€๏ธ","๐Ÿšด","๐Ÿšดโ€โ™‚๏ธ","๐Ÿคนโ€โ™€๏ธ","๐Ÿคน","๐Ÿคนโ€โ™‚๏ธ","๐Ÿ›€" -"๐Ÿ‘ซ","๐Ÿ‘ญ","๐Ÿ‘ฌ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ","๐Ÿ’‘","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ","๐Ÿ’","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ" +"๐Ÿค","๐Ÿ‘ซ","๐Ÿ‘ญ","๐Ÿ‘ฌ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ","๐Ÿ’‘","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ","๐Ÿ’","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ" ========================================= -"๐Ÿ—จ", "๐Ÿ‘ช" +"๐Ÿ—จ", "๐Ÿ‘ช", "๐Ÿ‡ฆ๐Ÿ‡จ", "๐Ÿ‡ง๐Ÿ‡ป", "๐Ÿ‡ฉ๐Ÿ‡ฌ", "๐Ÿ‡ช๐Ÿ‡ฆ", "๐Ÿ‡ญ๐Ÿ‡ฒ", "๐Ÿ‡ฒ๐Ÿ‡ซ", "๐Ÿ‡ธ๐Ÿ‡ฏ", "๐Ÿ‡น๐Ÿ‡ฆ", "๐Ÿ‡บ๐Ÿ‡ฒ" diff --git a/emoji_old/data4.txt b/emoji_old/data4.txt new file mode 100644 index 0000000..6fba402 --- /dev/null +++ b/emoji_old/data4.txt @@ -0,0 +1,654 @@ +"๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿ˜…","๐Ÿ˜‚","๐Ÿคฃ","๐Ÿฅฒ","โ˜บ๏ธ","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿ™‚","๐Ÿ™ƒ","๐Ÿ˜‰","๐Ÿ˜Œ","๐Ÿ˜","๐Ÿฅฐ","๐Ÿ˜˜","๐Ÿ˜—","๐Ÿ˜™","๐Ÿ˜š","๐Ÿ˜‹","๐Ÿ˜›","๐Ÿ˜","๐Ÿ˜œ","๐Ÿคช","๐Ÿคจ","๐Ÿง","๐Ÿค“","๐Ÿ˜Ž","๐Ÿฅธ","๐Ÿคฉ","๐Ÿฅณ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ˜ž","๐Ÿ˜”","๐Ÿ˜Ÿ","๐Ÿ˜•","๐Ÿ™","โ˜น๏ธ","๐Ÿ˜ฃ","๐Ÿ˜–","๐Ÿ˜ซ","๐Ÿ˜ฉ","๐Ÿฅบ","๐Ÿ˜ข","๐Ÿ˜ญ","๐Ÿ˜ค","๐Ÿ˜ ","๐Ÿ˜ก","๐Ÿคฌ","๐Ÿคฏ","๐Ÿ˜ณ","๐Ÿฅต","๐Ÿฅถ","๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿ˜ฑ","๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜“","๐Ÿค—","๐Ÿค”","๐Ÿคญ","๐Ÿคซ","๐Ÿคฅ","๐Ÿ˜ถ","๐Ÿ˜","๐Ÿ˜‘","๐Ÿ˜ฌ","๐Ÿ™„","๐Ÿ˜ฏ","๐Ÿ˜ฆ","๐Ÿ˜ง","๐Ÿ˜ฎ","๐Ÿ˜ฒ","๐Ÿฅฑ","๐Ÿ˜ด","๐Ÿคค","๐Ÿ˜ช","๐Ÿ˜ฎโ€๐Ÿ’จ","๐Ÿ˜ต","๐Ÿ˜ตโ€๐Ÿ’ซ","๐Ÿค","๐Ÿฅด","๐Ÿคข","๐Ÿคฎ","๐Ÿคง","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿค‘","๐Ÿค ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ‘น","๐Ÿ‘บ","๐Ÿคก","๐Ÿ’ฉ","๐Ÿ‘ป","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ‘ฝ","๐Ÿ‘พ","๐Ÿค–","๐ŸŽƒ","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น","๐Ÿ˜ป","๐Ÿ˜ผ","๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ", +"๐Ÿคฒ","๐Ÿคฒ๐Ÿป","๐Ÿคฒ๐Ÿผ","๐Ÿคฒ๐Ÿฝ","๐Ÿคฒ๐Ÿพ","๐Ÿคฒ๐Ÿฟ", +"๐Ÿ‘","๐Ÿ‘๐Ÿป","๐Ÿ‘๐Ÿผ","๐Ÿ‘๐Ÿฝ","๐Ÿ‘๐Ÿพ","๐Ÿ‘๐Ÿฟ", +"๐Ÿ™Œ","๐Ÿ™Œ๐Ÿป","๐Ÿ™Œ๐Ÿผ","๐Ÿ™Œ๐Ÿฝ","๐Ÿ™Œ๐Ÿพ","๐Ÿ™Œ๐Ÿฟ", +"๐Ÿ‘","๐Ÿ‘๐Ÿป","๐Ÿ‘๐Ÿผ","๐Ÿ‘๐Ÿฝ","๐Ÿ‘๐Ÿพ","๐Ÿ‘๐Ÿฟ", +"๐Ÿค", +"๐Ÿ‘","๐Ÿ‘๐Ÿป","๐Ÿ‘๐Ÿผ","๐Ÿ‘๐Ÿฝ","๐Ÿ‘๐Ÿพ","๐Ÿ‘๐Ÿฟ", +"๐Ÿ‘Ž","๐Ÿ‘Ž๐Ÿป","๐Ÿ‘Ž๐Ÿผ","๐Ÿ‘Ž๐Ÿฝ","๐Ÿ‘Ž๐Ÿพ","๐Ÿ‘Ž๐Ÿฟ", +"๐Ÿ‘Š","๐Ÿ‘Š๐Ÿป","๐Ÿ‘Š๐Ÿผ","๐Ÿ‘Š๐Ÿฝ","๐Ÿ‘Š๐Ÿพ","๐Ÿ‘Š๐Ÿฟ", +"โœŠ","โœŠ๐Ÿป","โœŠ๐Ÿผ","โœŠ๐Ÿฝ","โœŠ๐Ÿพ","โœŠ๐Ÿฟ", +"๐Ÿค›","๐Ÿค›๐Ÿป","๐Ÿค›๐Ÿผ","๐Ÿค›๐Ÿฝ","๐Ÿค›๐Ÿพ","๐Ÿค›๐Ÿฟ", +"๐Ÿคœ","๐Ÿคœ๐Ÿป","๐Ÿคœ๐Ÿผ","๐Ÿคœ๐Ÿฝ","๐Ÿคœ๐Ÿพ","๐Ÿคœ๐Ÿฟ", +"๐Ÿคž","๐Ÿคž๐Ÿป","๐Ÿคž๐Ÿผ","๐Ÿคž๐Ÿฝ","๐Ÿคž๐Ÿพ","๐Ÿคž๐Ÿฟ", +"โœŒ๏ธ","โœŒ๐Ÿป","โœŒ๐Ÿผ","โœŒ๐Ÿฝ","โœŒ๐Ÿพ","โœŒ๐Ÿฟ", +"๐ŸคŸ","๐ŸคŸ๐Ÿป","๐ŸคŸ๐Ÿผ","๐ŸคŸ๐Ÿฝ","๐ŸคŸ๐Ÿพ","๐ŸคŸ๐Ÿฟ", +"๐Ÿค˜","๐Ÿค˜๐Ÿป","๐Ÿค˜๐Ÿผ","๐Ÿค˜๐Ÿฝ","๐Ÿค˜๐Ÿพ","๐Ÿค˜๐Ÿฟ", +"๐Ÿ‘Œ","๐Ÿ‘Œ๐Ÿป","๐Ÿ‘Œ๐Ÿผ","๐Ÿ‘Œ๐Ÿฝ","๐Ÿ‘Œ๐Ÿพ","๐Ÿ‘Œ๐Ÿฟ", +"๐ŸคŒ","๐ŸคŒ๐Ÿป","๐ŸคŒ๐Ÿผ","๐ŸคŒ๐Ÿฝ","๐ŸคŒ๐Ÿพ","๐ŸคŒ๐Ÿฟ", +"๐Ÿค","๐Ÿค๐Ÿป","๐Ÿค๐Ÿผ","๐Ÿค๐Ÿฝ","๐Ÿค๐Ÿพ","๐Ÿค๐Ÿฟ", +"๐Ÿ‘ˆ","๐Ÿ‘ˆ๐Ÿป","๐Ÿ‘ˆ๐Ÿผ","๐Ÿ‘ˆ๐Ÿฝ","๐Ÿ‘ˆ๐Ÿพ","๐Ÿ‘ˆ๐Ÿฟ", +"๐Ÿ‘‰","๐Ÿ‘‰๐Ÿป","๐Ÿ‘‰๐Ÿผ","๐Ÿ‘‰๐Ÿฝ","๐Ÿ‘‰๐Ÿพ","๐Ÿ‘‰๐Ÿฟ", +"๐Ÿ‘†","๐Ÿ‘†๐Ÿป","๐Ÿ‘†๐Ÿผ","๐Ÿ‘†๐Ÿฝ","๐Ÿ‘†๐Ÿพ","๐Ÿ‘†๐Ÿฟ", +"๐Ÿ‘‡","๐Ÿ‘‡๐Ÿป","๐Ÿ‘‡๐Ÿผ","๐Ÿ‘‡๐Ÿฝ","๐Ÿ‘‡๐Ÿพ","๐Ÿ‘‡๐Ÿฟ", +"โ˜๏ธ","โ˜๐Ÿป","โ˜๐Ÿผ","โ˜๐Ÿฝ","โ˜๐Ÿพ","โ˜๐Ÿฟ", +"โœ‹","โœ‹๐Ÿป","โœ‹๐Ÿผ","โœ‹๐Ÿฝ","โœ‹๐Ÿพ","โœ‹๐Ÿฟ", +"๐Ÿคš","๐Ÿคš๐Ÿป","๐Ÿคš๐Ÿผ","๐Ÿคš๐Ÿฝ","๐Ÿคš๐Ÿพ","๐Ÿคš๐Ÿฟ", +"๐Ÿ–","๐Ÿ–๐Ÿป","๐Ÿ–๐Ÿผ","๐Ÿ–๐Ÿฝ","๐Ÿ–๐Ÿพ","๐Ÿ–๐Ÿฟ", +"๐Ÿ––","๐Ÿ––๐Ÿป","๐Ÿ––๐Ÿผ","๐Ÿ––๐Ÿฝ","๐Ÿ––๐Ÿพ","๐Ÿ––๐Ÿฟ", +"๐Ÿ‘‹","๐Ÿ‘‹๐Ÿป","๐Ÿ‘‹๐Ÿผ","๐Ÿ‘‹๐Ÿฝ","๐Ÿ‘‹๐Ÿพ","๐Ÿ‘‹๐Ÿฟ", +"๐Ÿค™","๐Ÿค™๐Ÿป","๐Ÿค™๐Ÿผ","๐Ÿค™๐Ÿฝ","๐Ÿค™๐Ÿพ","๐Ÿค™๐Ÿฟ", +"๐Ÿ’ช","๐Ÿ’ช๐Ÿป","๐Ÿ’ช๐Ÿผ","๐Ÿ’ช๐Ÿฝ","๐Ÿ’ช๐Ÿพ","๐Ÿ’ช๐Ÿฟ", +"๐Ÿฆพ", +"๐Ÿ–•","๐Ÿ–•๐Ÿป","๐Ÿ–•๐Ÿผ","๐Ÿ–•๐Ÿฝ","๐Ÿ–•๐Ÿพ","๐Ÿ–•๐Ÿฟ", +"โœ๏ธ","โœ๐Ÿป","โœ๐Ÿผ","โœ๐Ÿฝ","โœ๐Ÿพ","โœ๐Ÿฟ", +"๐Ÿ™","๐Ÿ™๐Ÿป","๐Ÿ™๐Ÿผ","๐Ÿ™๐Ÿฝ","๐Ÿ™๐Ÿพ","๐Ÿ™๐Ÿฟ", +"๐Ÿฆถ","๐Ÿฆถ๐Ÿป","๐Ÿฆถ๐Ÿผ","๐Ÿฆถ๐Ÿฝ","๐Ÿฆถ๐Ÿพ","๐Ÿฆถ๐Ÿฟ", +"๐Ÿฆต","๐Ÿฆต๐Ÿป","๐Ÿฆต๐Ÿผ","๐Ÿฆต๐Ÿฝ","๐Ÿฆต๐Ÿพ","๐Ÿฆต๐Ÿฟ", +"๐Ÿฆฟ","๐Ÿ’„","๐Ÿ’‹","๐Ÿ‘„","๐Ÿฆท","๐Ÿ‘…", +"๐Ÿ‘‚","๐Ÿ‘‚๐Ÿป","๐Ÿ‘‚๐Ÿผ","๐Ÿ‘‚๐Ÿฝ","๐Ÿ‘‚๐Ÿพ","๐Ÿ‘‚๐Ÿฟ", +"๐Ÿฆป","๐Ÿฆป๐Ÿป","๐Ÿฆป๐Ÿผ","๐Ÿฆป๐Ÿฝ","๐Ÿฆป๐Ÿพ","๐Ÿฆป๐Ÿฟ", +"๐Ÿ‘ƒ","๐Ÿ‘ƒ๐Ÿป","๐Ÿ‘ƒ๐Ÿผ","๐Ÿ‘ƒ๐Ÿฝ","๐Ÿ‘ƒ๐Ÿพ","๐Ÿ‘ƒ๐Ÿฟ", +"๐Ÿ‘ฃ","๐Ÿ‘","๐Ÿ‘€","๐Ÿซ€","๐Ÿซ","๐Ÿง ","๐Ÿ—ฃ","๐Ÿ‘ค","๐Ÿ‘ฅ","๐Ÿซ‚", +"๐Ÿ‘ถ","๐Ÿ‘ถ๐Ÿป","๐Ÿ‘ถ๐Ÿผ","๐Ÿ‘ถ๐Ÿฝ","๐Ÿ‘ถ๐Ÿพ","๐Ÿ‘ถ๐Ÿฟ", +"๐Ÿ‘ง","๐Ÿ‘ง๐Ÿป","๐Ÿ‘ง๐Ÿผ","๐Ÿ‘ง๐Ÿฝ","๐Ÿ‘ง๐Ÿพ","๐Ÿ‘ง๐Ÿฟ", +"๐Ÿง’","๐Ÿง’๐Ÿป","๐Ÿง’๐Ÿผ","๐Ÿง’๐Ÿฝ","๐Ÿง’๐Ÿพ","๐Ÿง’๐Ÿฟ", +"๐Ÿ‘ฆ","๐Ÿ‘ฆ๐Ÿป","๐Ÿ‘ฆ๐Ÿผ","๐Ÿ‘ฆ๐Ÿฝ","๐Ÿ‘ฆ๐Ÿพ","๐Ÿ‘ฆ๐Ÿฟ", +"๐Ÿ‘ฉ","๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟ", +"๐Ÿง‘","๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฟ", +"๐Ÿ‘จ","๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘ฉโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฑ", +"๐Ÿง‘โ€๐Ÿฆฑ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฑ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฑ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฑ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฑ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฑ", +"๐Ÿ‘จโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฑ", +"๐Ÿ‘ฉโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฐ", +"๐Ÿง‘โ€๐Ÿฆฐ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฐ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฐ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฐ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฐ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฐ", +"๐Ÿ‘จโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฐ", +"๐Ÿ‘ฑโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ฑ","๐Ÿ‘ฑ๐Ÿป","๐Ÿ‘ฑ๐Ÿผ","๐Ÿ‘ฑ๐Ÿฝ","๐Ÿ‘ฑ๐Ÿพ","๐Ÿ‘ฑ๐Ÿฟ", +"๐Ÿ‘ฑโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆณ", +"๐Ÿง‘โ€๐Ÿฆณ","๐Ÿง‘๐Ÿปโ€๐Ÿฆณ","๐Ÿง‘๐Ÿผโ€๐Ÿฆณ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆณ","๐Ÿง‘๐Ÿพโ€๐Ÿฆณ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆณ", +"๐Ÿ‘จโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆณ", +"๐Ÿ‘ฉโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฒ", +"๐Ÿง‘โ€๐Ÿฆฒ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฒ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฒ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฒ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฒ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฒ", +"๐Ÿ‘จโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฒ", +"๐Ÿง”โ€โ™€๏ธ","๐Ÿง”๐Ÿปโ€โ™€๏ธ","๐Ÿง”๐Ÿผโ€โ™€๏ธ","๐Ÿง”๐Ÿฝโ€โ™€๏ธ","๐Ÿง”๐Ÿพโ€โ™€๏ธ","๐Ÿง”๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง”","๐Ÿง”๐Ÿป","๐Ÿง”๐Ÿผ","๐Ÿง”๐Ÿฝ","๐Ÿง”๐Ÿพ","๐Ÿง”๐Ÿฟ", +"๐Ÿง”โ€โ™‚๏ธ","๐Ÿง”๐Ÿปโ€โ™‚๏ธ","๐Ÿง”๐Ÿผโ€โ™‚๏ธ","๐Ÿง”๐Ÿฝโ€โ™‚๏ธ","๐Ÿง”๐Ÿพโ€โ™‚๏ธ","๐Ÿง”๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ต","๐Ÿ‘ต๐Ÿป","๐Ÿ‘ต๐Ÿผ","๐Ÿ‘ต๐Ÿฝ","๐Ÿ‘ต๐Ÿพ","๐Ÿ‘ต๐Ÿฟ", +"๐Ÿง“","๐Ÿง“๐Ÿป","๐Ÿง“๐Ÿผ","๐Ÿง“๐Ÿฝ","๐Ÿง“๐Ÿพ","๐Ÿง“๐Ÿฟ", +"๐Ÿ‘ด","๐Ÿ‘ด๐Ÿป","๐Ÿ‘ด๐Ÿผ","๐Ÿ‘ด๐Ÿฝ","๐Ÿ‘ด๐Ÿพ","๐Ÿ‘ด๐Ÿฟ", +"๐Ÿ‘ฒ","๐Ÿ‘ฒ๐Ÿป","๐Ÿ‘ฒ๐Ÿผ","๐Ÿ‘ฒ๐Ÿฝ","๐Ÿ‘ฒ๐Ÿพ","๐Ÿ‘ฒ๐Ÿฟ", +"๐Ÿ‘ณโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ณ","๐Ÿ‘ณ๐Ÿป","๐Ÿ‘ณ๐Ÿผ","๐Ÿ‘ณ๐Ÿฝ","๐Ÿ‘ณ๐Ÿพ","๐Ÿ‘ณ๐Ÿฟ", +"๐Ÿ‘ณโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿง•","๐Ÿง•๐Ÿป","๐Ÿง•๐Ÿผ","๐Ÿง•๐Ÿฝ","๐Ÿง•๐Ÿพ","๐Ÿง•๐Ÿฟ", +"๐Ÿ‘ฎโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ฎ","๐Ÿ‘ฎ๐Ÿป","๐Ÿ‘ฎ๐Ÿผ","๐Ÿ‘ฎ๐Ÿฝ","๐Ÿ‘ฎ๐Ÿพ","๐Ÿ‘ฎ๐Ÿฟ", +"๐Ÿ‘ฎโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ทโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ท","๐Ÿ‘ท๐Ÿป","๐Ÿ‘ท๐Ÿผ","๐Ÿ‘ท๐Ÿฝ","๐Ÿ‘ท๐Ÿพ","๐Ÿ‘ท๐Ÿฟ", +"๐Ÿ‘ทโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’‚โ€โ™€๏ธ","๐Ÿ’‚๐Ÿปโ€โ™€๏ธ","๐Ÿ’‚๐Ÿผโ€โ™€๏ธ","๐Ÿ’‚๐Ÿฝโ€โ™€๏ธ","๐Ÿ’‚๐Ÿพโ€โ™€๏ธ","๐Ÿ’‚๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ’‚","๐Ÿ’‚๐Ÿป","๐Ÿ’‚๐Ÿผ","๐Ÿ’‚๐Ÿฝ","๐Ÿ’‚๐Ÿพ","๐Ÿ’‚๐Ÿฟ", +"๐Ÿ’‚โ€โ™‚๏ธ","๐Ÿ’‚๐Ÿปโ€โ™‚๏ธ","๐Ÿ’‚๐Ÿผโ€โ™‚๏ธ","๐Ÿ’‚๐Ÿฝโ€โ™‚๏ธ","๐Ÿ’‚๐Ÿพโ€โ™‚๏ธ","๐Ÿ’‚๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ•ต๏ธโ€โ™€๏ธ","๐Ÿ•ต๐Ÿปโ€โ™€๏ธ","๐Ÿ•ต๐Ÿผโ€โ™€๏ธ","๐Ÿ•ต๐Ÿฝโ€โ™€๏ธ","๐Ÿ•ต๐Ÿพโ€โ™€๏ธ","๐Ÿ•ต๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ•ต๏ธ","๐Ÿ•ต๐Ÿป","๐Ÿ•ต๐Ÿผ","๐Ÿ•ต๐Ÿฝ","๐Ÿ•ต๐Ÿพ","๐Ÿ•ต๐Ÿฟ", +"๐Ÿ•ต๏ธโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿปโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿผโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿฝโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿพโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿปโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿผโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿฝโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿพโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿฟโ€โš•๏ธ", +"๐Ÿง‘โ€โš•๏ธ","๐Ÿง‘๐Ÿปโ€โš•๏ธ","๐Ÿง‘๐Ÿผโ€โš•๏ธ","๐Ÿง‘๐Ÿฝโ€โš•๏ธ","๐Ÿง‘๐Ÿพโ€โš•๏ธ","๐Ÿง‘๐Ÿฟโ€โš•๏ธ", +"๐Ÿ‘จโ€โš•๏ธ","๐Ÿ‘จ๐Ÿปโ€โš•๏ธ","๐Ÿ‘จ๐Ÿผโ€โš•๏ธ","๐Ÿ‘จ๐Ÿฝโ€โš•๏ธ","๐Ÿ‘จ๐Ÿพโ€โš•๏ธ","๐Ÿ‘จ๐Ÿฟโ€โš•๏ธ", +"๐Ÿ‘ฉโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿปโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿผโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿพโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŒพ", +"๐Ÿง‘โ€๐ŸŒพ","๐Ÿง‘๐Ÿปโ€๐ŸŒพ","๐Ÿง‘๐Ÿผโ€๐ŸŒพ","๐Ÿง‘๐Ÿฝโ€๐ŸŒพ","๐Ÿง‘๐Ÿพโ€๐ŸŒพ","๐Ÿง‘๐Ÿฟโ€๐ŸŒพ", +"๐Ÿ‘จโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿปโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿผโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿฝโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿพโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿฟโ€๐ŸŒพ", +"๐Ÿ‘ฉโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿณ", +"๐Ÿง‘โ€๐Ÿณ","๐Ÿง‘๐Ÿปโ€๐Ÿณ","๐Ÿง‘๐Ÿผโ€๐Ÿณ","๐Ÿง‘๐Ÿฝโ€๐Ÿณ","๐Ÿง‘๐Ÿพโ€๐Ÿณ","๐Ÿง‘๐Ÿฟโ€๐Ÿณ", +"๐Ÿ‘จโ€๐Ÿณ","๐Ÿ‘จ๐Ÿปโ€๐Ÿณ","๐Ÿ‘จ๐Ÿผโ€๐Ÿณ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿณ","๐Ÿ‘จ๐Ÿพโ€๐Ÿณ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿณ", +"๐Ÿ‘ฉโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿผโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿพโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŽ“", +"๐Ÿง‘โ€๐ŸŽ“","๐Ÿง‘๐Ÿปโ€๐ŸŽ“","๐Ÿง‘๐Ÿผโ€๐ŸŽ“","๐Ÿง‘๐Ÿฝโ€๐ŸŽ“","๐Ÿง‘๐Ÿพโ€๐ŸŽ“","๐Ÿง‘๐Ÿฟโ€๐ŸŽ“", +"๐Ÿ‘จโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿปโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿผโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿฝโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿพโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿฟโ€๐ŸŽ“", +"๐Ÿ‘ฉโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿผโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿพโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŽค", +"๐Ÿง‘โ€๐ŸŽค","๐Ÿง‘๐Ÿปโ€๐ŸŽค","๐Ÿง‘๐Ÿผโ€๐ŸŽค","๐Ÿง‘๐Ÿฝโ€๐ŸŽค","๐Ÿง‘๐Ÿพโ€๐ŸŽค","๐Ÿง‘๐Ÿฟโ€๐ŸŽค", +"๐Ÿ‘จโ€๐ŸŽค","๐Ÿ‘จ๐Ÿปโ€๐ŸŽค","๐Ÿ‘จ๐Ÿผโ€๐ŸŽค","๐Ÿ‘จ๐Ÿฝโ€๐ŸŽค","๐Ÿ‘จ๐Ÿพโ€๐ŸŽค","๐Ÿ‘จ๐Ÿฟโ€๐ŸŽค", +"๐Ÿ‘ฉโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿซ", +"๐Ÿง‘โ€๐Ÿซ","๐Ÿง‘๐Ÿปโ€๐Ÿซ","๐Ÿง‘๐Ÿผโ€๐Ÿซ","๐Ÿง‘๐Ÿฝโ€๐Ÿซ","๐Ÿง‘๐Ÿพโ€๐Ÿซ","๐Ÿง‘๐Ÿฟโ€๐Ÿซ", +"๐Ÿ‘จโ€๐Ÿซ","๐Ÿ‘จ๐Ÿปโ€๐Ÿซ","๐Ÿ‘จ๐Ÿผโ€๐Ÿซ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿซ","๐Ÿ‘จ๐Ÿพโ€๐Ÿซ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿซ", +"๐Ÿ‘ฉโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿญ", +"๐Ÿง‘โ€๐Ÿญ","๐Ÿง‘๐Ÿปโ€๐Ÿญ","๐Ÿง‘๐Ÿผโ€๐Ÿญ","๐Ÿง‘๐Ÿฝโ€๐Ÿญ","๐Ÿง‘๐Ÿพโ€๐Ÿญ","๐Ÿง‘๐Ÿฟโ€๐Ÿญ", +"๐Ÿ‘จโ€๐Ÿญ","๐Ÿ‘จ๐Ÿปโ€๐Ÿญ","๐Ÿ‘จ๐Ÿผโ€๐Ÿญ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿญ","๐Ÿ‘จ๐Ÿพโ€๐Ÿญ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿญ", +"๐Ÿ‘ฉโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ’ป", +"๐Ÿง‘โ€๐Ÿ’ป","๐Ÿง‘๐Ÿปโ€๐Ÿ’ป","๐Ÿง‘๐Ÿผโ€๐Ÿ’ป","๐Ÿง‘๐Ÿฝโ€๐Ÿ’ป","๐Ÿง‘๐Ÿพโ€๐Ÿ’ป","๐Ÿง‘๐Ÿฟโ€๐Ÿ’ป", +"๐Ÿ‘จโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿผโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿฝโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿพโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿฟโ€๐Ÿ’ป", +"๐Ÿ‘ฉโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ’ผ", +"๐Ÿง‘โ€๐Ÿ’ผ","๐Ÿง‘๐Ÿปโ€๐Ÿ’ผ","๐Ÿง‘๐Ÿผโ€๐Ÿ’ผ","๐Ÿง‘๐Ÿฝโ€๐Ÿ’ผ","๐Ÿง‘๐Ÿพโ€๐Ÿ’ผ","๐Ÿง‘๐Ÿฟโ€๐Ÿ’ผ", +"๐Ÿ‘จโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿผโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿพโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿ’ผ", +"๐Ÿ‘ฉโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ”ง", +"๐Ÿง‘โ€๐Ÿ”ง","๐Ÿง‘๐Ÿปโ€๐Ÿ”ง","๐Ÿง‘๐Ÿผโ€๐Ÿ”ง","๐Ÿง‘๐Ÿฝโ€๐Ÿ”ง","๐Ÿง‘๐Ÿพโ€๐Ÿ”ง","๐Ÿง‘๐Ÿฟโ€๐Ÿ”ง", +"๐Ÿ‘จโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿปโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿผโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿฝโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿพโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿฟโ€๐Ÿ”ง", +"๐Ÿ‘ฉโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ”ฌ", +"๐Ÿง‘โ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿปโ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿผโ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿฝโ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿพโ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿฟโ€๐Ÿ”ฌ", +"๐Ÿ‘จโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿปโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿผโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿพโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿ”ฌ", +"๐Ÿ‘ฉโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿผโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿพโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŽจ", +"๐Ÿง‘โ€๐ŸŽจ","๐Ÿง‘๐Ÿปโ€๐ŸŽจ","๐Ÿง‘๐Ÿผโ€๐ŸŽจ","๐Ÿง‘๐Ÿฝโ€๐ŸŽจ","๐Ÿง‘๐Ÿพโ€๐ŸŽจ","๐Ÿง‘๐Ÿฟโ€๐ŸŽจ", +"๐Ÿ‘จโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿปโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿผโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿฝโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿพโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿฟโ€๐ŸŽจ", +"๐Ÿ‘ฉโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿš’", +"๐Ÿง‘โ€๐Ÿš’","๐Ÿง‘๐Ÿปโ€๐Ÿš’","๐Ÿง‘๐Ÿผโ€๐Ÿš’","๐Ÿง‘๐Ÿฝโ€๐Ÿš’","๐Ÿง‘๐Ÿพโ€๐Ÿš’","๐Ÿง‘๐Ÿฟโ€๐Ÿš’", +"๐Ÿ‘จโ€๐Ÿš’","๐Ÿ‘จ๐Ÿปโ€๐Ÿš’","๐Ÿ‘จ๐Ÿผโ€๐Ÿš’","๐Ÿ‘จ๐Ÿฝโ€๐Ÿš’","๐Ÿ‘จ๐Ÿพโ€๐Ÿš’","๐Ÿ‘จ๐Ÿฟโ€๐Ÿš’", +"๐Ÿ‘ฉโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿปโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿผโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿฝโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿพโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿฟโ€โœˆ๏ธ", +"๐Ÿง‘โ€โœˆ๏ธ","๐Ÿง‘๐Ÿปโ€โœˆ๏ธ","๐Ÿง‘๐Ÿผโ€โœˆ๏ธ","๐Ÿง‘๐Ÿฝโ€โœˆ๏ธ","๐Ÿง‘๐Ÿพโ€โœˆ๏ธ","๐Ÿง‘๐Ÿฟโ€โœˆ๏ธ", +"๐Ÿ‘จโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿปโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿผโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿฝโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿพโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿฟโ€โœˆ๏ธ", +"๐Ÿ‘ฉโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿš€", +"๐Ÿง‘โ€๐Ÿš€","๐Ÿง‘๐Ÿปโ€๐Ÿš€","๐Ÿง‘๐Ÿผโ€๐Ÿš€","๐Ÿง‘๐Ÿฝโ€๐Ÿš€","๐Ÿง‘๐Ÿพโ€๐Ÿš€","๐Ÿง‘๐Ÿฟโ€๐Ÿš€", +"๐Ÿ‘จโ€๐Ÿš€","๐Ÿ‘จ๐Ÿปโ€๐Ÿš€","๐Ÿ‘จ๐Ÿผโ€๐Ÿš€","๐Ÿ‘จ๐Ÿฝโ€๐Ÿš€","๐Ÿ‘จ๐Ÿพโ€๐Ÿš€","๐Ÿ‘จ๐Ÿฟโ€๐Ÿš€", +"๐Ÿ‘ฉโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿปโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿผโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿฝโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿพโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿฟโ€โš–๏ธ", +"๐Ÿง‘โ€โš–๏ธ","๐Ÿง‘๐Ÿปโ€โš–๏ธ","๐Ÿง‘๐Ÿผโ€โš–๏ธ","๐Ÿง‘๐Ÿฝโ€โš–๏ธ","๐Ÿง‘๐Ÿพโ€โš–๏ธ","๐Ÿง‘๐Ÿฟโ€โš–๏ธ", +"๐Ÿ‘จโ€โš–๏ธ","๐Ÿ‘จ๐Ÿปโ€โš–๏ธ","๐Ÿ‘จ๐Ÿผโ€โš–๏ธ","๐Ÿ‘จ๐Ÿฝโ€โš–๏ธ","๐Ÿ‘จ๐Ÿพโ€โš–๏ธ","๐Ÿ‘จ๐Ÿฟโ€โš–๏ธ", +"๐Ÿ‘ฐโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ฐ","๐Ÿ‘ฐ๐Ÿป","๐Ÿ‘ฐ๐Ÿผ","๐Ÿ‘ฐ๐Ÿฝ","๐Ÿ‘ฐ๐Ÿพ","๐Ÿ‘ฐ๐Ÿฟ", +"๐Ÿ‘ฐโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคตโ€โ™€๏ธ","๐Ÿคต๐Ÿปโ€โ™€๏ธ","๐Ÿคต๐Ÿผโ€โ™€๏ธ","๐Ÿคต๐Ÿฝโ€โ™€๏ธ","๐Ÿคต๐Ÿพโ€โ™€๏ธ","๐Ÿคต๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคต","๐Ÿคต๐Ÿป","๐Ÿคต๐Ÿผ","๐Ÿคต๐Ÿฝ","๐Ÿคต๐Ÿพ","๐Ÿคต๐Ÿฟ", +"๐Ÿคตโ€โ™‚๏ธ","๐Ÿคต๐Ÿปโ€โ™‚๏ธ","๐Ÿคต๐Ÿผโ€โ™‚๏ธ","๐Ÿคต๐Ÿฝโ€โ™‚๏ธ","๐Ÿคต๐Ÿพโ€โ™‚๏ธ","๐Ÿคต๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ธ","๐Ÿ‘ธ๐Ÿป","๐Ÿ‘ธ๐Ÿผ","๐Ÿ‘ธ๐Ÿฝ","๐Ÿ‘ธ๐Ÿพ","๐Ÿ‘ธ๐Ÿฟ", +"๐Ÿคด","๐Ÿคด๐Ÿป","๐Ÿคด๐Ÿผ","๐Ÿคด๐Ÿฝ","๐Ÿคด๐Ÿพ","๐Ÿคด๐Ÿฟ", +"๐Ÿฅท","๐Ÿฅท๐Ÿป","๐Ÿฅท๐Ÿผ","๐Ÿฅท๐Ÿฝ","๐Ÿฅท๐Ÿพ","๐Ÿฅท๐Ÿฟ", +"๐Ÿฆธโ€โ™€๏ธ","๐Ÿฆธ๐Ÿปโ€โ™€๏ธ","๐Ÿฆธ๐Ÿผโ€โ™€๏ธ","๐Ÿฆธ๐Ÿฝโ€โ™€๏ธ","๐Ÿฆธ๐Ÿพโ€โ™€๏ธ","๐Ÿฆธ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿฆธ","๐Ÿฆธ๐Ÿป","๐Ÿฆธ๐Ÿผ","๐Ÿฆธ๐Ÿฝ","๐Ÿฆธ๐Ÿพ","๐Ÿฆธ๐Ÿฟ", +"๐Ÿฆธโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿปโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿผโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿฝโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿพโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿฆนโ€โ™€๏ธ","๐Ÿฆน๐Ÿปโ€โ™€๏ธ","๐Ÿฆน๐Ÿผโ€โ™€๏ธ","๐Ÿฆน๐Ÿฝโ€โ™€๏ธ","๐Ÿฆน๐Ÿพโ€โ™€๏ธ","๐Ÿฆน๐Ÿฟโ€โ™€๏ธ", +"๐Ÿฆน","๐Ÿฆน๐Ÿป","๐Ÿฆน๐Ÿผ","๐Ÿฆน๐Ÿฝ","๐Ÿฆน๐Ÿพ","๐Ÿฆน๐Ÿฟ", +"๐Ÿฆนโ€โ™‚๏ธ","๐Ÿฆน๐Ÿปโ€โ™‚๏ธ","๐Ÿฆน๐Ÿผโ€โ™‚๏ธ","๐Ÿฆน๐Ÿฝโ€โ™‚๏ธ","๐Ÿฆน๐Ÿพโ€โ™‚๏ธ","๐Ÿฆน๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคถ","๐Ÿคถ๐Ÿป","๐Ÿคถ๐Ÿผ","๐Ÿคถ๐Ÿฝ","๐Ÿคถ๐Ÿพ","๐Ÿคถ๐Ÿฟ", +"๐Ÿง‘โ€๐ŸŽ„","๐Ÿง‘๐Ÿปโ€๐ŸŽ„","๐Ÿง‘๐Ÿผโ€๐ŸŽ„","๐Ÿง‘๐Ÿฝโ€๐ŸŽ„","๐Ÿง‘๐Ÿพโ€๐ŸŽ„","๐Ÿง‘๐Ÿฟโ€๐ŸŽ„", +"๐ŸŽ…","๐ŸŽ…๐Ÿป","๐ŸŽ…๐Ÿผ","๐ŸŽ…๐Ÿฝ","๐ŸŽ…๐Ÿพ","๐ŸŽ…๐Ÿฟ", +"๐Ÿง™โ€โ™€๏ธ","๐Ÿง™๐Ÿปโ€โ™€๏ธ","๐Ÿง™๐Ÿผโ€โ™€๏ธ","๐Ÿง™๐Ÿฝโ€โ™€๏ธ","๐Ÿง™๐Ÿพโ€โ™€๏ธ","๐Ÿง™๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง™","๐Ÿง™๐Ÿป","๐Ÿง™๐Ÿผ","๐Ÿง™๐Ÿฝ","๐Ÿง™๐Ÿพ","๐Ÿง™๐Ÿฟ", +"๐Ÿง™โ€โ™‚๏ธ","๐Ÿง™๐Ÿปโ€โ™‚๏ธ","๐Ÿง™๐Ÿผโ€โ™‚๏ธ","๐Ÿง™๐Ÿฝโ€โ™‚๏ธ","๐Ÿง™๐Ÿพโ€โ™‚๏ธ","๐Ÿง™๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ","๐Ÿง๐Ÿปโ€โ™€๏ธ","๐Ÿง๐Ÿผโ€โ™€๏ธ","๐Ÿง๐Ÿฝโ€โ™€๏ธ","๐Ÿง๐Ÿพโ€โ™€๏ธ","๐Ÿง๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง","๐Ÿง๐Ÿป","๐Ÿง๐Ÿผ","๐Ÿง๐Ÿฝ","๐Ÿง๐Ÿพ","๐Ÿง๐Ÿฟ", +"๐Ÿงโ€โ™‚๏ธ","๐Ÿง๐Ÿปโ€โ™‚๏ธ","๐Ÿง๐Ÿผโ€โ™‚๏ธ","๐Ÿง๐Ÿฝโ€โ™‚๏ธ","๐Ÿง๐Ÿพโ€โ™‚๏ธ","๐Ÿง๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿง›โ€โ™€๏ธ","๐Ÿง›๐Ÿปโ€โ™€๏ธ","๐Ÿง›๐Ÿผโ€โ™€๏ธ","๐Ÿง›๐Ÿฝโ€โ™€๏ธ","๐Ÿง›๐Ÿพโ€โ™€๏ธ","๐Ÿง›๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง›","๐Ÿง›๐Ÿป","๐Ÿง›๐Ÿผ","๐Ÿง›๐Ÿฝ","๐Ÿง›๐Ÿพ","๐Ÿง›๐Ÿฟ", +"๐Ÿง›โ€โ™‚๏ธ","๐Ÿง›๐Ÿปโ€โ™‚๏ธ","๐Ÿง›๐Ÿผโ€โ™‚๏ธ","๐Ÿง›๐Ÿฝโ€โ™‚๏ธ","๐Ÿง›๐Ÿพโ€โ™‚๏ธ","๐Ÿง›๐Ÿฟโ€โ™‚๏ธ", +"๐ŸงŸโ€โ™€๏ธ","๐ŸงŸ","๐ŸงŸโ€โ™‚๏ธ","๐Ÿงžโ€โ™€๏ธ","๐Ÿงž","๐Ÿงžโ€โ™‚๏ธ", +"๐Ÿงœโ€โ™€๏ธ","๐Ÿงœ๐Ÿปโ€โ™€๏ธ","๐Ÿงœ๐Ÿผโ€โ™€๏ธ","๐Ÿงœ๐Ÿฝโ€โ™€๏ธ","๐Ÿงœ๐Ÿพโ€โ™€๏ธ","๐Ÿงœ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿงœ","๐Ÿงœ๐Ÿป","๐Ÿงœ๐Ÿผ","๐Ÿงœ๐Ÿฝ","๐Ÿงœ๐Ÿพ","๐Ÿงœ๐Ÿฟ", +"๐Ÿงœโ€โ™‚๏ธ","๐Ÿงœ๐Ÿปโ€โ™‚๏ธ","๐Ÿงœ๐Ÿผโ€โ™‚๏ธ","๐Ÿงœ๐Ÿฝโ€โ™‚๏ธ","๐Ÿงœ๐Ÿพโ€โ™‚๏ธ","๐Ÿงœ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿงšโ€โ™€๏ธ","๐Ÿงš๐Ÿปโ€โ™€๏ธ","๐Ÿงš๐Ÿผโ€โ™€๏ธ","๐Ÿงš๐Ÿฝโ€โ™€๏ธ","๐Ÿงš๐Ÿพโ€โ™€๏ธ","๐Ÿงš๐Ÿฟโ€โ™€๏ธ", +"๐Ÿงš","๐Ÿงš๐Ÿป","๐Ÿงš๐Ÿผ","๐Ÿงš๐Ÿฝ","๐Ÿงš๐Ÿพ","๐Ÿงš๐Ÿฟ", +"๐Ÿงšโ€โ™‚๏ธ","๐Ÿงš๐Ÿปโ€โ™‚๏ธ","๐Ÿงš๐Ÿผโ€โ™‚๏ธ","๐Ÿงš๐Ÿฝโ€โ™‚๏ธ","๐Ÿงš๐Ÿพโ€โ™‚๏ธ","๐Ÿงš๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ผ","๐Ÿ‘ผ๐Ÿป","๐Ÿ‘ผ๐Ÿผ","๐Ÿ‘ผ๐Ÿฝ","๐Ÿ‘ผ๐Ÿพ","๐Ÿ‘ผ๐Ÿฟ", +"๐Ÿคฐ","๐Ÿคฐ๐Ÿป","๐Ÿคฐ๐Ÿผ","๐Ÿคฐ๐Ÿฝ","๐Ÿคฐ๐Ÿพ","๐Ÿคฐ๐Ÿฟ", +"๐Ÿคฑ","๐Ÿคฑ๐Ÿป","๐Ÿคฑ๐Ÿผ","๐Ÿคฑ๐Ÿฝ","๐Ÿคฑ๐Ÿพ","๐Ÿคฑ๐Ÿฟ", +"๐Ÿ‘ฉโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿผ", +"๐Ÿง‘โ€๐Ÿผ","๐Ÿง‘๐Ÿปโ€๐Ÿผ","๐Ÿง‘๐Ÿผโ€๐Ÿผ","๐Ÿง‘๐Ÿฝโ€๐Ÿผ","๐Ÿง‘๐Ÿพโ€๐Ÿผ","๐Ÿง‘๐Ÿฟโ€๐Ÿผ", +"๐Ÿ‘จโ€๐Ÿผ","๐Ÿ‘จ๐Ÿปโ€๐Ÿผ","๐Ÿ‘จ๐Ÿผโ€๐Ÿผ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿผ","๐Ÿ‘จ๐Ÿพโ€๐Ÿผ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿผ", +"๐Ÿ™‡โ€โ™€๏ธ","๐Ÿ™‡๐Ÿปโ€โ™€๏ธ","๐Ÿ™‡๐Ÿผโ€โ™€๏ธ","๐Ÿ™‡๐Ÿฝโ€โ™€๏ธ","๐Ÿ™‡๐Ÿพโ€โ™€๏ธ","๐Ÿ™‡๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™‡","๐Ÿ™‡๐Ÿป","๐Ÿ™‡๐Ÿผ","๐Ÿ™‡๐Ÿฝ","๐Ÿ™‡๐Ÿพ","๐Ÿ™‡๐Ÿฟ", +"๐Ÿ™‡โ€โ™‚๏ธ","๐Ÿ™‡๐Ÿปโ€โ™‚๏ธ","๐Ÿ™‡๐Ÿผโ€โ™‚๏ธ","๐Ÿ™‡๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™‡๐Ÿพโ€โ™‚๏ธ","๐Ÿ™‡๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’โ€โ™€๏ธ","๐Ÿ’๐Ÿปโ€โ™€๏ธ","๐Ÿ’๐Ÿผโ€โ™€๏ธ","๐Ÿ’๐Ÿฝโ€โ™€๏ธ","๐Ÿ’๐Ÿพโ€โ™€๏ธ","๐Ÿ’๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ’","๐Ÿ’๐Ÿป","๐Ÿ’๐Ÿผ","๐Ÿ’๐Ÿฝ","๐Ÿ’๐Ÿพ","๐Ÿ’๐Ÿฟ", +"๐Ÿ’โ€โ™‚๏ธ","๐Ÿ’๐Ÿปโ€โ™‚๏ธ","๐Ÿ’๐Ÿผโ€โ™‚๏ธ","๐Ÿ’๐Ÿฝโ€โ™‚๏ธ","๐Ÿ’๐Ÿพโ€โ™‚๏ธ","๐Ÿ’๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™…โ€โ™€๏ธ","๐Ÿ™…๐Ÿปโ€โ™€๏ธ","๐Ÿ™…๐Ÿผโ€โ™€๏ธ","๐Ÿ™…๐Ÿฝโ€โ™€๏ธ","๐Ÿ™…๐Ÿพโ€โ™€๏ธ","๐Ÿ™…๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™…","๐Ÿ™…๐Ÿป","๐Ÿ™…๐Ÿผ","๐Ÿ™…๐Ÿฝ","๐Ÿ™…๐Ÿพ","๐Ÿ™…๐Ÿฟ", +"๐Ÿ™…โ€โ™‚๏ธ","๐Ÿ™…๐Ÿปโ€โ™‚๏ธ","๐Ÿ™…๐Ÿผโ€โ™‚๏ธ","๐Ÿ™…๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™…๐Ÿพโ€โ™‚๏ธ","๐Ÿ™…๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™†โ€โ™€๏ธ","๐Ÿ™†๐Ÿปโ€โ™€๏ธ","๐Ÿ™†๐Ÿผโ€โ™€๏ธ","๐Ÿ™†๐Ÿฝโ€โ™€๏ธ","๐Ÿ™†๐Ÿพโ€โ™€๏ธ","๐Ÿ™†๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™†","๐Ÿ™†๐Ÿป","๐Ÿ™†๐Ÿผ","๐Ÿ™†๐Ÿฝ","๐Ÿ™†๐Ÿพ","๐Ÿ™†๐Ÿฟ", +"๐Ÿ™†โ€โ™‚๏ธ","๐Ÿ™†๐Ÿปโ€โ™‚๏ธ","๐Ÿ™†๐Ÿผโ€โ™‚๏ธ","๐Ÿ™†๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™†๐Ÿพโ€โ™‚๏ธ","๐Ÿ™†๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™‹โ€โ™€๏ธ","๐Ÿ™‹๐Ÿปโ€โ™€๏ธ","๐Ÿ™‹๐Ÿผโ€โ™€๏ธ","๐Ÿ™‹๐Ÿฝโ€โ™€๏ธ","๐Ÿ™‹๐Ÿพโ€โ™€๏ธ","๐Ÿ™‹๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™‹","๐Ÿ™‹๐Ÿป","๐Ÿ™‹๐Ÿผ","๐Ÿ™‹๐Ÿฝ","๐Ÿ™‹๐Ÿพ","๐Ÿ™‹๐Ÿฟ", +"๐Ÿ™‹โ€โ™‚๏ธ","๐Ÿ™‹๐Ÿปโ€โ™‚๏ธ","๐Ÿ™‹๐Ÿผโ€โ™‚๏ธ","๐Ÿ™‹๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™‹๐Ÿพโ€โ™‚๏ธ","๐Ÿ™‹๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ","๐Ÿง๐Ÿปโ€โ™€๏ธ","๐Ÿง๐Ÿผโ€โ™€๏ธ","๐Ÿง๐Ÿฝโ€โ™€๏ธ","๐Ÿง๐Ÿพโ€โ™€๏ธ","๐Ÿง๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง","๐Ÿง๐Ÿป","๐Ÿง๐Ÿผ","๐Ÿง๐Ÿฝ","๐Ÿง๐Ÿพ","๐Ÿง๐Ÿฟ", +"๐Ÿงโ€โ™‚๏ธ","๐Ÿง๐Ÿปโ€โ™‚๏ธ","๐Ÿง๐Ÿผโ€โ™‚๏ธ","๐Ÿง๐Ÿฝโ€โ™‚๏ธ","๐Ÿง๐Ÿพโ€โ™‚๏ธ","๐Ÿง๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคฆโ€โ™€๏ธ","๐Ÿคฆ๐Ÿปโ€โ™€๏ธ","๐Ÿคฆ๐Ÿผโ€โ™€๏ธ","๐Ÿคฆ๐Ÿฝโ€โ™€๏ธ","๐Ÿคฆ๐Ÿพโ€โ™€๏ธ","๐Ÿคฆ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคฆ","๐Ÿคฆ๐Ÿป","๐Ÿคฆ๐Ÿผ","๐Ÿคฆ๐Ÿฝ","๐Ÿคฆ๐Ÿพ","๐Ÿคฆ๐Ÿฟ", +"๐Ÿคฆโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿปโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿผโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿฝโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿพโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคทโ€โ™€๏ธ","๐Ÿคท๐Ÿปโ€โ™€๏ธ","๐Ÿคท๐Ÿผโ€โ™€๏ธ","๐Ÿคท๐Ÿฝโ€โ™€๏ธ","๐Ÿคท๐Ÿพโ€โ™€๏ธ","๐Ÿคท๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคท","๐Ÿคท๐Ÿป","๐Ÿคท๐Ÿผ","๐Ÿคท๐Ÿฝ","๐Ÿคท๐Ÿพ","๐Ÿคท๐Ÿฟ", +"๐Ÿคทโ€โ™‚๏ธ","๐Ÿคท๐Ÿปโ€โ™‚๏ธ","๐Ÿคท๐Ÿผโ€โ™‚๏ธ","๐Ÿคท๐Ÿฝโ€โ™‚๏ธ","๐Ÿคท๐Ÿพโ€โ™‚๏ธ","๐Ÿคท๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™Žโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿปโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿผโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿฝโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿพโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™Ž","๐Ÿ™Ž๐Ÿป","๐Ÿ™Ž๐Ÿผ","๐Ÿ™Ž๐Ÿฝ","๐Ÿ™Ž๐Ÿพ","๐Ÿ™Ž๐Ÿฟ", +"๐Ÿ™Žโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿปโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿผโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿพโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™โ€โ™€๏ธ","๐Ÿ™๐Ÿปโ€โ™€๏ธ","๐Ÿ™๐Ÿผโ€โ™€๏ธ","๐Ÿ™๐Ÿฝโ€โ™€๏ธ","๐Ÿ™๐Ÿพโ€โ™€๏ธ","๐Ÿ™๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™","๐Ÿ™๐Ÿป","๐Ÿ™๐Ÿผ","๐Ÿ™๐Ÿฝ","๐Ÿ™๐Ÿพ","๐Ÿ™๐Ÿฟ", +"๐Ÿ™โ€โ™‚๏ธ","๐Ÿ™๐Ÿปโ€โ™‚๏ธ","๐Ÿ™๐Ÿผโ€โ™‚๏ธ","๐Ÿ™๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™๐Ÿพโ€โ™‚๏ธ","๐Ÿ™๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’‡โ€โ™€๏ธ","๐Ÿ’‡๐Ÿปโ€โ™€๏ธ","๐Ÿ’‡๐Ÿผโ€โ™€๏ธ","๐Ÿ’‡๐Ÿฝโ€โ™€๏ธ","๐Ÿ’‡๐Ÿพโ€โ™€๏ธ","๐Ÿ’‡๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ’‡","๐Ÿ’‡๐Ÿป","๐Ÿ’‡๐Ÿผ","๐Ÿ’‡๐Ÿฝ","๐Ÿ’‡๐Ÿพ","๐Ÿ’‡๐Ÿฟ", +"๐Ÿ’‡โ€โ™‚๏ธ","๐Ÿ’‡๐Ÿปโ€โ™‚๏ธ","๐Ÿ’‡๐Ÿผโ€โ™‚๏ธ","๐Ÿ’‡๐Ÿฝโ€โ™‚๏ธ","๐Ÿ’‡๐Ÿพโ€โ™‚๏ธ","๐Ÿ’‡๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’†โ€โ™€๏ธ","๐Ÿ’†๐Ÿปโ€โ™€๏ธ","๐Ÿ’†๐Ÿผโ€โ™€๏ธ","๐Ÿ’†๐Ÿฝโ€โ™€๏ธ","๐Ÿ’†๐Ÿพโ€โ™€๏ธ","๐Ÿ’†๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ’†","๐Ÿ’†๐Ÿป","๐Ÿ’†๐Ÿผ","๐Ÿ’†๐Ÿฝ","๐Ÿ’†๐Ÿพ","๐Ÿ’†๐Ÿฟ", +"๐Ÿ’†โ€โ™‚๏ธ","๐Ÿ’†๐Ÿปโ€โ™‚๏ธ","๐Ÿ’†๐Ÿผโ€โ™‚๏ธ","๐Ÿ’†๐Ÿฝโ€โ™‚๏ธ","๐Ÿ’†๐Ÿพโ€โ™‚๏ธ","๐Ÿ’†๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿง–โ€โ™€๏ธ","๐Ÿง–๐Ÿปโ€โ™€๏ธ","๐Ÿง–๐Ÿผโ€โ™€๏ธ","๐Ÿง–๐Ÿฝโ€โ™€๏ธ","๐Ÿง–๐Ÿพโ€โ™€๏ธ","๐Ÿง–๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง–","๐Ÿง–๐Ÿป","๐Ÿง–๐Ÿผ","๐Ÿง–๐Ÿฝ","๐Ÿง–๐Ÿพ","๐Ÿง–๐Ÿฟ", +"๐Ÿง–โ€โ™‚๏ธ","๐Ÿง–๐Ÿปโ€โ™‚๏ธ","๐Ÿง–๐Ÿผโ€โ™‚๏ธ","๐Ÿง–๐Ÿฝโ€โ™‚๏ธ","๐Ÿง–๐Ÿพโ€โ™‚๏ธ","๐Ÿง–๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’…","๐Ÿ’…๐Ÿป","๐Ÿ’…๐Ÿผ","๐Ÿ’…๐Ÿฝ","๐Ÿ’…๐Ÿพ","๐Ÿ’…๐Ÿฟ", +"๐Ÿคณ","๐Ÿคณ๐Ÿป","๐Ÿคณ๐Ÿผ","๐Ÿคณ๐Ÿฝ","๐Ÿคณ๐Ÿพ","๐Ÿคณ๐Ÿฟ", +"๐Ÿ’ƒ","๐Ÿ’ƒ๐Ÿป","๐Ÿ’ƒ๐Ÿผ","๐Ÿ’ƒ๐Ÿฝ","๐Ÿ’ƒ๐Ÿพ","๐Ÿ’ƒ๐Ÿฟ", +"๐Ÿ•บ","๐Ÿ•บ๐Ÿป","๐Ÿ•บ๐Ÿผ","๐Ÿ•บ๐Ÿฝ","๐Ÿ•บ๐Ÿพ","๐Ÿ•บ๐Ÿฟ", +"๐Ÿ‘ฏโ€โ™€๏ธ","๐Ÿ‘ฏ","๐Ÿ‘ฏโ€โ™‚๏ธ", +"๐Ÿ•ด","๐Ÿ•ด๐Ÿป","๐Ÿ•ด๐Ÿผ","๐Ÿ•ด๐Ÿฝ","๐Ÿ•ด๐Ÿพ","๐Ÿ•ด๐Ÿฟ", +"๐Ÿ‘ฉโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฝ", +"๐Ÿง‘โ€๐Ÿฆฝ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฝ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฝ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฝ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฝ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฝ", +"๐Ÿ‘จโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฝ", +"๐Ÿ‘ฉโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆผ", +"๐Ÿง‘โ€๐Ÿฆผ","๐Ÿง‘๐Ÿปโ€๐Ÿฆผ","๐Ÿง‘๐Ÿผโ€๐Ÿฆผ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆผ","๐Ÿง‘๐Ÿพโ€๐Ÿฆผ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆผ", +"๐Ÿ‘จโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆผ", +"๐Ÿšถโ€โ™€๏ธ","๐Ÿšถ๐Ÿปโ€โ™€๏ธ","๐Ÿšถ๐Ÿผโ€โ™€๏ธ","๐Ÿšถ๐Ÿฝโ€โ™€๏ธ","๐Ÿšถ๐Ÿพโ€โ™€๏ธ","๐Ÿšถ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿšถ","๐Ÿšถ๐Ÿป","๐Ÿšถ๐Ÿผ","๐Ÿšถ๐Ÿฝ","๐Ÿšถ๐Ÿพ","๐Ÿšถ๐Ÿฟ", +"๐Ÿšถโ€โ™‚๏ธ","๐Ÿšถ๐Ÿปโ€โ™‚๏ธ","๐Ÿšถ๐Ÿผโ€โ™‚๏ธ","๐Ÿšถ๐Ÿฝโ€โ™‚๏ธ","๐Ÿšถ๐Ÿพโ€โ™‚๏ธ","๐Ÿšถ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฏ", +"๐Ÿง‘โ€๐Ÿฆฏ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฏ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฏ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฏ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฏ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฏ", +"๐Ÿ‘จโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฏ", +"๐ŸงŽโ€โ™€๏ธ","๐ŸงŽ๐Ÿปโ€โ™€๏ธ","๐ŸงŽ๐Ÿผโ€โ™€๏ธ","๐ŸงŽ๐Ÿฝโ€โ™€๏ธ","๐ŸงŽ๐Ÿพโ€โ™€๏ธ","๐ŸงŽ๐Ÿฟโ€โ™€๏ธ", +"๐ŸงŽ","๐ŸงŽ๐Ÿป","๐ŸงŽ๐Ÿผ","๐ŸงŽ๐Ÿฝ","๐ŸงŽ๐Ÿพ","๐ŸงŽ๐Ÿฟ", +"๐ŸงŽโ€โ™‚๏ธ","๐ŸงŽ๐Ÿปโ€โ™‚๏ธ","๐ŸงŽ๐Ÿผโ€โ™‚๏ธ","๐ŸงŽ๐Ÿฝโ€โ™‚๏ธ","๐ŸงŽ๐Ÿพโ€โ™‚๏ธ","๐ŸงŽ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿƒโ€โ™€๏ธ","๐Ÿƒ๐Ÿปโ€โ™€๏ธ","๐Ÿƒ๐Ÿผโ€โ™€๏ธ","๐Ÿƒ๐Ÿฝโ€โ™€๏ธ","๐Ÿƒ๐Ÿพโ€โ™€๏ธ","๐Ÿƒ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿƒ","๐Ÿƒ๐Ÿป","๐Ÿƒ๐Ÿผ","๐Ÿƒ๐Ÿฝ","๐Ÿƒ๐Ÿพ","๐Ÿƒ๐Ÿฟ", +"๐Ÿƒโ€โ™‚๏ธ","๐Ÿƒ๐Ÿปโ€โ™‚๏ธ","๐Ÿƒ๐Ÿผโ€โ™‚๏ธ","๐Ÿƒ๐Ÿฝโ€โ™‚๏ธ","๐Ÿƒ๐Ÿพโ€โ™‚๏ธ","๐Ÿƒ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ","๐Ÿง๐Ÿปโ€โ™€๏ธ","๐Ÿง๐Ÿผโ€โ™€๏ธ","๐Ÿง๐Ÿฝโ€โ™€๏ธ","๐Ÿง๐Ÿพโ€โ™€๏ธ","๐Ÿง๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง","๐Ÿง๐Ÿป","๐Ÿง๐Ÿผ","๐Ÿง๐Ÿฝ","๐Ÿง๐Ÿพ","๐Ÿง๐Ÿฟ", +"๐Ÿงโ€โ™‚๏ธ","๐Ÿง๐Ÿปโ€โ™‚๏ธ","๐Ÿง๐Ÿผโ€โ™‚๏ธ","๐Ÿง๐Ÿฝโ€โ™‚๏ธ","๐Ÿง๐Ÿพโ€โ™‚๏ธ","๐Ÿง๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ซ","๐Ÿ‘ซ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ซ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ซ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ซ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ซ๐Ÿฟ", +"๐Ÿ‘ญ","๐Ÿ‘ญ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ญ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ญ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ญ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ญ๐Ÿฟ", +"๐Ÿ‘ฌ","๐Ÿ‘ฌ๐Ÿป","๐Ÿ‘จ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฌ๐Ÿผ","๐Ÿ‘จ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฌ๐Ÿฝ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฌ๐Ÿพ","๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฌ๐Ÿฟ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ", +"๐Ÿ’‘","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ", +"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ", +"๐Ÿ’","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ", +"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿชข","๐Ÿงถ","๐Ÿงต","๐Ÿชก","๐Ÿงฅ","๐Ÿฅผ","๐Ÿฆบ","๐Ÿ‘š","๐Ÿ‘•","๐Ÿ‘–","๐Ÿฉฒ","๐Ÿฉณ","๐Ÿ‘”","๐Ÿ‘—","๐Ÿ‘™","๐Ÿฉฑ","๐Ÿ‘˜","๐Ÿฅป","๐Ÿฉด","๐Ÿฅฟ","๐Ÿ‘ ","๐Ÿ‘ก","๐Ÿ‘ข","๐Ÿ‘ž","๐Ÿ‘Ÿ","๐Ÿฅพ","๐Ÿงฆ","๐Ÿงค","๐Ÿงฃ","๐ŸŽฉ","๐Ÿงข","๐Ÿ‘’","๐ŸŽ“","โ›‘","๐Ÿช–","๐Ÿ‘‘","๐Ÿ’","๐Ÿ‘","๐Ÿ‘›","๐Ÿ‘œ","๐Ÿ’ผ","๐ŸŽ’","๐Ÿงณ","๐Ÿ‘“","๐Ÿ•ถ","๐Ÿฅฝ","๐ŸŒ‚" + + +"๐Ÿถ","๐Ÿฑ","๐Ÿญ","๐Ÿน","๐Ÿฐ","๐ŸฆŠ","๐Ÿป","๐Ÿผ","๐Ÿปโ€โ„๏ธ","๐Ÿจ","๐Ÿฏ","๐Ÿฆ","๐Ÿฎ","๐Ÿท","๐Ÿฝ","๐Ÿธ","๐Ÿต","๐Ÿ™ˆ","๐Ÿ™‰","๐Ÿ™Š","๐Ÿ’","๐Ÿ”","๐Ÿง","๐Ÿฆ","๐Ÿค","๐Ÿฃ","๐Ÿฅ","๐Ÿฆ†","๐Ÿฆ…","๐Ÿฆ‰","๐Ÿฆ‡","๐Ÿบ","๐Ÿ—","๐Ÿด","๐Ÿฆ„","๐Ÿ","๐Ÿชฑ","๐Ÿ›","๐Ÿฆ‹","๐ŸŒ","๐Ÿž","๐Ÿœ","๐Ÿชฐ","๐Ÿชฒ","๐Ÿชณ","๐ŸฆŸ","๐Ÿฆ—","๐Ÿ•ท","๐Ÿ•ธ","๐Ÿฆ‚","๐Ÿข","๐Ÿ","๐ŸฆŽ","๐Ÿฆ–","๐Ÿฆ•","๐Ÿ™","๐Ÿฆ‘","๐Ÿฆ","๐Ÿฆž","๐Ÿฆ€","๐Ÿก","๐Ÿ ","๐ŸŸ","๐Ÿฌ","๐Ÿณ","๐Ÿ‹","๐Ÿฆˆ","๐Ÿฆญ","๐ŸŠ","๐Ÿ…","๐Ÿ†","๐Ÿฆ“","๐Ÿฆ","๐Ÿฆง","๐Ÿฆฃ","๐Ÿ˜","๐Ÿฆ›","๐Ÿฆ","๐Ÿช","๐Ÿซ","๐Ÿฆ’","๐Ÿฆ˜","๐Ÿฆฌ","๐Ÿƒ","๐Ÿ‚","๐Ÿ„","๐ŸŽ","๐Ÿ–","๐Ÿ","๐Ÿ‘","๐Ÿฆ™","๐Ÿ","๐ŸฆŒ","๐Ÿ•","๐Ÿฉ","๐Ÿฆฎ","๐Ÿ•โ€๐Ÿฆบ","๐Ÿˆ","๐Ÿˆโ€โฌ›","๐Ÿชถ","๐Ÿ“","๐Ÿฆƒ","๐Ÿฆค","๐Ÿฆš","๐Ÿฆœ","๐Ÿฆข","๐Ÿฆฉ","๐Ÿ•Š","๐Ÿ‡","๐Ÿฆ","๐Ÿฆจ","๐Ÿฆก","๐Ÿฆซ","๐Ÿฆฆ","๐Ÿฆฅ","๐Ÿ","๐Ÿ€","๐Ÿฟ","๐Ÿฆ”","๐Ÿพ","๐Ÿ‰","๐Ÿฒ","๐ŸŒต","๐ŸŽ„","๐ŸŒฒ","๐ŸŒณ","๐ŸŒด","๐Ÿชต","๐ŸŒฑ","๐ŸŒฟ","โ˜˜๏ธ","๐Ÿ€","๐ŸŽ","๐Ÿชด","๐ŸŽ‹","๐Ÿƒ","๐Ÿ‚","๐Ÿ","๐Ÿ„","๐Ÿš","๐Ÿชจ","๐ŸŒพ","๐Ÿ’","๐ŸŒท","๐ŸŒน","๐Ÿฅ€","๐ŸŒบ","๐ŸŒธ","๐ŸŒผ","๐ŸŒป","๐ŸŒž","๐ŸŒ","๐ŸŒ›","๐ŸŒœ","๐ŸŒš","๐ŸŒ•","๐ŸŒ–","๐ŸŒ—","๐ŸŒ˜","๐ŸŒ‘","๐ŸŒ’","๐ŸŒ“","๐ŸŒ”","๐ŸŒ™","๐ŸŒŽ","๐ŸŒ","๐ŸŒ","๐Ÿช","๐Ÿ’ซ","โญ๏ธ","๐ŸŒŸ","โœจ","โšก๏ธ","โ˜„๏ธ","๐Ÿ’ฅ","๐Ÿ”ฅ","๐ŸŒช","๐ŸŒˆ","โ˜€๏ธ","๐ŸŒค","โ›…๏ธ","๐ŸŒฅ","โ˜๏ธ","๐ŸŒฆ","๐ŸŒง","โ›ˆ","๐ŸŒฉ","๐ŸŒจ","โ„๏ธ","โ˜ƒ๏ธ","โ›„๏ธ","๐ŸŒฌ","๐Ÿ’จ","๐Ÿ’ง","๐Ÿ’ฆ","โ˜”๏ธ","โ˜‚๏ธ","๐ŸŒŠ","๐ŸŒซ" + + +"๐Ÿ","๐ŸŽ","๐Ÿ","๐ŸŠ","๐Ÿ‹","๐ŸŒ","๐Ÿ‰","๐Ÿ‡","๐Ÿ“","๐Ÿซ","๐Ÿˆ","๐Ÿ’","๐Ÿ‘","๐Ÿฅญ","๐Ÿ","๐Ÿฅฅ","๐Ÿฅ","๐Ÿ…","๐Ÿ†","๐Ÿฅ‘","๐Ÿฅฆ","๐Ÿฅฌ","๐Ÿฅ’","๐ŸŒถ","๐Ÿซ‘","๐ŸŒฝ","๐Ÿฅ•","๐Ÿซ’","๐Ÿง„","๐Ÿง…","๐Ÿฅ”","๐Ÿ ","๐Ÿฅ","๐Ÿฅฏ","๐Ÿž","๐Ÿฅ–","๐Ÿฅจ","๐Ÿง€","๐Ÿฅš","๐Ÿณ","๐Ÿงˆ","๐Ÿฅž","๐Ÿง‡","๐Ÿฅ“","๐Ÿฅฉ","๐Ÿ—","๐Ÿ–","๐Ÿฆด","๐ŸŒญ","๐Ÿ”","๐ŸŸ","๐Ÿ•","๐Ÿซ“","๐Ÿฅช","๐Ÿฅ™","๐Ÿง†","๐ŸŒฎ","๐ŸŒฏ","๐Ÿซ”","๐Ÿฅ—","๐Ÿฅ˜","๐Ÿซ•","๐Ÿฅซ","๐Ÿ","๐Ÿœ","๐Ÿฒ","๐Ÿ›","๐Ÿฃ","๐Ÿฑ","๐ŸฅŸ","๐Ÿฆช","๐Ÿค","๐Ÿ™","๐Ÿš","๐Ÿ˜","๐Ÿฅ","๐Ÿฅ ","๐Ÿฅฎ","๐Ÿข","๐Ÿก","๐Ÿง","๐Ÿจ","๐Ÿฆ","๐Ÿฅง","๐Ÿง","๐Ÿฐ","๐ŸŽ‚","๐Ÿฎ","๐Ÿญ","๐Ÿฌ","๐Ÿซ","๐Ÿฟ","๐Ÿฉ","๐Ÿช","๐ŸŒฐ","๐Ÿฅœ","๐Ÿฏ","๐Ÿฅ›","๐Ÿผ","๐Ÿซ–","โ˜•๏ธ","๐Ÿต","๐Ÿงƒ","๐Ÿฅค","๐Ÿง‹","๐Ÿถ","๐Ÿบ","๐Ÿป","๐Ÿฅ‚","๐Ÿท","๐Ÿฅƒ","๐Ÿธ","๐Ÿน","๐Ÿง‰","๐Ÿพ","๐ŸงŠ","๐Ÿฅ„","๐Ÿด","๐Ÿฝ","๐Ÿฅฃ","๐Ÿฅก","๐Ÿฅข","๐Ÿง‚" + + +"โšฝ๏ธ","๐Ÿ€","๐Ÿˆ","โšพ๏ธ","๐ŸฅŽ","๐ŸŽพ","๐Ÿ","๐Ÿ‰","๐Ÿฅ","๐ŸŽฑ","๐Ÿช€","๐Ÿ“","๐Ÿธ","๐Ÿ’","๐Ÿ‘","๐Ÿฅ","๐Ÿ","๐Ÿชƒ","๐Ÿฅ…","โ›ณ๏ธ","๐Ÿช","๐Ÿน","๐ŸŽฃ","๐Ÿคฟ","๐ŸฅŠ","๐Ÿฅ‹","๐ŸŽฝ","๐Ÿ›น","๐Ÿ›ผ","๐Ÿ›ท","โ›ธ","๐ŸฅŒ","๐ŸŽฟ","โ›ท","๐Ÿ‚","๐Ÿช‚", +"๐Ÿ‹๏ธโ€โ™€๏ธ","๐Ÿ‹๐Ÿปโ€โ™€๏ธ","๐Ÿ‹๐Ÿผโ€โ™€๏ธ","๐Ÿ‹๐Ÿฝโ€โ™€๏ธ","๐Ÿ‹๐Ÿพโ€โ™€๏ธ","๐Ÿ‹๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‹๏ธ","๐Ÿ‹๐Ÿป","๐Ÿ‹๐Ÿผ","๐Ÿ‹๐Ÿฝ","๐Ÿ‹๐Ÿพ","๐Ÿ‹๐Ÿฟ", +"๐Ÿ‹๏ธโ€โ™‚๏ธ","๐Ÿ‹๐Ÿปโ€โ™‚๏ธ","๐Ÿ‹๐Ÿผโ€โ™‚๏ธ","๐Ÿ‹๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‹๐Ÿพโ€โ™‚๏ธ","๐Ÿ‹๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคผโ€โ™€๏ธ","๐Ÿคผ","๐Ÿคผโ€โ™‚๏ธ", +"๐Ÿคธโ€โ™€๏ธ","๐Ÿคธ๐Ÿปโ€โ™€๏ธ","๐Ÿคธ๐Ÿผโ€โ™€๏ธ","๐Ÿคธ๐Ÿฝโ€โ™€๏ธ","๐Ÿคธ๐Ÿพโ€โ™€๏ธ","๐Ÿคธ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคธ","๐Ÿคธ๐Ÿป","๐Ÿคธ๐Ÿผ","๐Ÿคธ๐Ÿฝ","๐Ÿคธ๐Ÿพ","๐Ÿคธ๐Ÿฟ", +"๐Ÿคธโ€โ™‚๏ธ","๐Ÿคธ๐Ÿปโ€โ™‚๏ธ","๐Ÿคธ๐Ÿผโ€โ™‚๏ธ","๐Ÿคธ๐Ÿฝโ€โ™‚๏ธ","๐Ÿคธ๐Ÿพโ€โ™‚๏ธ","๐Ÿคธ๐Ÿฟโ€โ™‚๏ธ", +"โ›น๏ธโ€โ™€๏ธ","โ›น๐Ÿปโ€โ™€๏ธ","โ›น๐Ÿผโ€โ™€๏ธ","โ›น๐Ÿฝโ€โ™€๏ธ","โ›น๐Ÿพโ€โ™€๏ธ","โ›น๐Ÿฟโ€โ™€๏ธ", +"โ›น๏ธ","โ›น๐Ÿป","โ›น๐Ÿผ","โ›น๐Ÿฝ","โ›น๐Ÿพ","โ›น๐Ÿฟ", +"โ›น๏ธโ€โ™‚๏ธ","โ›น๐Ÿปโ€โ™‚๏ธ","โ›น๐Ÿผโ€โ™‚๏ธ","โ›น๐Ÿฝโ€โ™‚๏ธ","โ›น๐Ÿพโ€โ™‚๏ธ","โ›น๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคบ", +"๐Ÿคพโ€โ™€๏ธ","๐Ÿคพ๐Ÿปโ€โ™€๏ธ","๐Ÿคพ๐Ÿผโ€โ™€๏ธ","๐Ÿคพ๐Ÿฝโ€โ™€๏ธ","๐Ÿคพ๐Ÿพโ€โ™€๏ธ","๐Ÿคพ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคพ","๐Ÿคพ๐Ÿป","๐Ÿคพ๐Ÿผ","๐Ÿคพ๐Ÿฝ","๐Ÿคพ๐Ÿพ","๐Ÿคพ๐Ÿฟ", +"๐Ÿคพโ€โ™‚๏ธ","๐Ÿคพ๐Ÿปโ€โ™‚๏ธ","๐Ÿคพ๐Ÿผโ€โ™‚๏ธ","๐Ÿคพ๐Ÿฝโ€โ™‚๏ธ","๐Ÿคพ๐Ÿพโ€โ™‚๏ธ","๐Ÿคพ๐Ÿฟโ€โ™‚๏ธ", +"๐ŸŒ๏ธโ€โ™€๏ธ","๐ŸŒ๐Ÿปโ€โ™€๏ธ","๐ŸŒ๐Ÿผโ€โ™€๏ธ","๐ŸŒ๐Ÿฝโ€โ™€๏ธ","๐ŸŒ๐Ÿพโ€โ™€๏ธ","๐ŸŒ๐Ÿฟโ€โ™€๏ธ", +"๐ŸŒ๏ธ","๐ŸŒ๐Ÿป","๐ŸŒ๐Ÿผ","๐ŸŒ๐Ÿฝ","๐ŸŒ๐Ÿพ","๐ŸŒ๐Ÿฟ", +"๐ŸŒ๏ธโ€โ™‚๏ธ","๐ŸŒ๐Ÿปโ€โ™‚๏ธ","๐ŸŒ๐Ÿผโ€โ™‚๏ธ","๐ŸŒ๐Ÿฝโ€โ™‚๏ธ","๐ŸŒ๐Ÿพโ€โ™‚๏ธ","๐ŸŒ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‡","๐Ÿ‡๐Ÿป","๐Ÿ‡๐Ÿผ","๐Ÿ‡๐Ÿฝ","๐Ÿ‡๐Ÿพ","๐Ÿ‡๐Ÿฟ", +"๐Ÿง˜โ€โ™€๏ธ","๐Ÿง˜๐Ÿปโ€โ™€๏ธ","๐Ÿง˜๐Ÿผโ€โ™€๏ธ","๐Ÿง˜๐Ÿฝโ€โ™€๏ธ","๐Ÿง˜๐Ÿพโ€โ™€๏ธ","๐Ÿง˜๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง˜","๐Ÿง˜๐Ÿป","๐Ÿง˜๐Ÿผ","๐Ÿง˜๐Ÿฝ","๐Ÿง˜๐Ÿพ","๐Ÿง˜๐Ÿฟ", +"๐Ÿง˜โ€โ™‚๏ธ","๐Ÿง˜๐Ÿปโ€โ™‚๏ธ","๐Ÿง˜๐Ÿผโ€โ™‚๏ธ","๐Ÿง˜๐Ÿฝโ€โ™‚๏ธ","๐Ÿง˜๐Ÿพโ€โ™‚๏ธ","๐Ÿง˜๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ„โ€โ™€๏ธ","๐Ÿ„๐Ÿปโ€โ™€๏ธ","๐Ÿ„๐Ÿผโ€โ™€๏ธ","๐Ÿ„๐Ÿฝโ€โ™€๏ธ","๐Ÿ„๐Ÿพโ€โ™€๏ธ","๐Ÿ„๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ„","๐Ÿ„๐Ÿป","๐Ÿ„๐Ÿผ","๐Ÿ„๐Ÿฝ","๐Ÿ„๐Ÿพ","๐Ÿ„๐Ÿฟ", +"๐Ÿ„โ€โ™‚๏ธ","๐Ÿ„๐Ÿปโ€โ™‚๏ธ","๐Ÿ„๐Ÿผโ€โ™‚๏ธ","๐Ÿ„๐Ÿฝโ€โ™‚๏ธ","๐Ÿ„๐Ÿพโ€โ™‚๏ธ","๐Ÿ„๐Ÿฟโ€โ™‚๏ธ", +"๐ŸŠโ€โ™€๏ธ","๐ŸŠ๐Ÿปโ€โ™€๏ธ","๐ŸŠ๐Ÿผโ€โ™€๏ธ","๐ŸŠ๐Ÿฝโ€โ™€๏ธ","๐ŸŠ๐Ÿพโ€โ™€๏ธ","๐ŸŠ๐Ÿฟโ€โ™€๏ธ", +"๐ŸŠ","๐ŸŠ๐Ÿป","๐ŸŠ๐Ÿผ","๐ŸŠ๐Ÿฝ","๐ŸŠ๐Ÿพ","๐ŸŠ๐Ÿฟ", +"๐ŸŠโ€โ™‚๏ธ","๐ŸŠ๐Ÿปโ€โ™‚๏ธ","๐ŸŠ๐Ÿผโ€โ™‚๏ธ","๐ŸŠ๐Ÿฝโ€โ™‚๏ธ","๐ŸŠ๐Ÿพโ€โ™‚๏ธ","๐ŸŠ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคฝโ€โ™€๏ธ","๐Ÿคฝ๐Ÿปโ€โ™€๏ธ","๐Ÿคฝ๐Ÿผโ€โ™€๏ธ","๐Ÿคฝ๐Ÿฝโ€โ™€๏ธ","๐Ÿคฝ๐Ÿพโ€โ™€๏ธ","๐Ÿคฝ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคฝ","๐Ÿคฝ๐Ÿป","๐Ÿคฝ๐Ÿผ","๐Ÿคฝ๐Ÿฝ","๐Ÿคฝ๐Ÿพ","๐Ÿคฝ๐Ÿฟ", +"๐Ÿคฝโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿปโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿผโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿฝโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿพโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿšฃโ€โ™€๏ธ","๐Ÿšฃ๐Ÿปโ€โ™€๏ธ","๐Ÿšฃ๐Ÿผโ€โ™€๏ธ","๐Ÿšฃ๐Ÿฝโ€โ™€๏ธ","๐Ÿšฃ๐Ÿพโ€โ™€๏ธ","๐Ÿšฃ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿšฃ","๐Ÿšฃ๐Ÿป","๐Ÿšฃ๐Ÿผ","๐Ÿšฃ๐Ÿฝ","๐Ÿšฃ๐Ÿพ","๐Ÿšฃ๐Ÿฟ", +"๐Ÿšฃโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿปโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿผโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿฝโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿพโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿง—โ€โ™€๏ธ","๐Ÿง—๐Ÿปโ€โ™€๏ธ","๐Ÿง—๐Ÿผโ€โ™€๏ธ","๐Ÿง—๐Ÿฝโ€โ™€๏ธ","๐Ÿง—๐Ÿพโ€โ™€๏ธ","๐Ÿง—๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง—","๐Ÿง—๐Ÿป","๐Ÿง—๐Ÿผ","๐Ÿง—๐Ÿฝ","๐Ÿง—๐Ÿพ","๐Ÿง—๐Ÿฟ", +"๐Ÿง—โ€โ™‚๏ธ","๐Ÿง—๐Ÿปโ€โ™‚๏ธ","๐Ÿง—๐Ÿผโ€โ™‚๏ธ","๐Ÿง—๐Ÿฝโ€โ™‚๏ธ","๐Ÿง—๐Ÿพโ€โ™‚๏ธ","๐Ÿง—๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿšตโ€โ™€๏ธ","๐Ÿšต๐Ÿปโ€โ™€๏ธ","๐Ÿšต๐Ÿผโ€โ™€๏ธ","๐Ÿšต๐Ÿฝโ€โ™€๏ธ","๐Ÿšต๐Ÿพโ€โ™€๏ธ","๐Ÿšต๐Ÿฟโ€โ™€๏ธ", +"๐Ÿšต","๐Ÿšต๐Ÿป","๐Ÿšต๐Ÿผ","๐Ÿšต๐Ÿฝ","๐Ÿšต๐Ÿพ","๐Ÿšต๐Ÿฟ", +"๐Ÿšตโ€โ™‚๏ธ","๐Ÿšต๐Ÿปโ€โ™‚๏ธ","๐Ÿšต๐Ÿผโ€โ™‚๏ธ","๐Ÿšต๐Ÿฝโ€โ™‚๏ธ","๐Ÿšต๐Ÿพโ€โ™‚๏ธ","๐Ÿšต๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿšดโ€โ™€๏ธ","๐Ÿšด๐Ÿปโ€โ™€๏ธ","๐Ÿšด๐Ÿผโ€โ™€๏ธ","๐Ÿšด๐Ÿฝโ€โ™€๏ธ","๐Ÿšด๐Ÿพโ€โ™€๏ธ","๐Ÿšด๐Ÿฟโ€โ™€๏ธ", +"๐Ÿšด","๐Ÿšด๐Ÿป","๐Ÿšด๐Ÿผ","๐Ÿšด๐Ÿฝ","๐Ÿšด๐Ÿพ","๐Ÿšด๐Ÿฟ", +"๐Ÿšดโ€โ™‚๏ธ","๐Ÿšด๐Ÿปโ€โ™‚๏ธ","๐Ÿšด๐Ÿผโ€โ™‚๏ธ","๐Ÿšด๐Ÿฝโ€โ™‚๏ธ","๐Ÿšด๐Ÿพโ€โ™‚๏ธ","๐Ÿšด๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ†","๐Ÿฅ‡","๐Ÿฅˆ","๐Ÿฅ‰","๐Ÿ…","๐ŸŽ–","๐Ÿต","๐ŸŽ—","๐ŸŽซ","๐ŸŽŸ","๐ŸŽช", +"๐Ÿคนโ€โ™€๏ธ","๐Ÿคน๐Ÿปโ€โ™€๏ธ","๐Ÿคน๐Ÿผโ€โ™€๏ธ","๐Ÿคน๐Ÿฝโ€โ™€๏ธ","๐Ÿคน๐Ÿพโ€โ™€๏ธ","๐Ÿคน๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคน","๐Ÿคน๐Ÿป","๐Ÿคน๐Ÿผ","๐Ÿคน๐Ÿฝ","๐Ÿคน๐Ÿพ","๐Ÿคน๐Ÿฟ", +"๐Ÿคนโ€โ™‚๏ธ","๐Ÿคน๐Ÿปโ€โ™‚๏ธ","๐Ÿคน๐Ÿผโ€โ™‚๏ธ","๐Ÿคน๐Ÿฝโ€โ™‚๏ธ","๐Ÿคน๐Ÿพโ€โ™‚๏ธ","๐Ÿคน๐Ÿฟโ€โ™‚๏ธ", +"๐ŸŽญ","๐Ÿฉฐ","๐ŸŽจ","๐ŸŽฌ","๐ŸŽค","๐ŸŽง","๐ŸŽผ","๐ŸŽน","๐Ÿฅ","๐Ÿช˜","๐ŸŽท","๐ŸŽบ","๐Ÿช—","๐ŸŽธ","๐Ÿช•","๐ŸŽป","๐ŸŽฒ","โ™Ÿ","๐ŸŽฏ","๐ŸŽณ","๐ŸŽฎ","๐ŸŽฐ","๐Ÿงฉ" + + +"๐Ÿš—","๐Ÿš•","๐Ÿš™","๐ŸšŒ","๐ŸšŽ","๐ŸŽ","๐Ÿš“","๐Ÿš‘","๐Ÿš’","๐Ÿš","๐Ÿ›ป","๐Ÿšš","๐Ÿš›","๐Ÿšœ","๐Ÿฆฏ","๐Ÿฆฝ","๐Ÿฆผ","๐Ÿ›ด","๐Ÿšฒ","๐Ÿ›ต","๐Ÿ","๐Ÿ›บ","๐Ÿšจ","๐Ÿš”","๐Ÿš","๐Ÿš˜","๐Ÿš–","๐Ÿšก","๐Ÿš ","๐ŸšŸ","๐Ÿšƒ","๐Ÿš‹","๐Ÿšž","๐Ÿš","๐Ÿš„","๐Ÿš…","๐Ÿšˆ","๐Ÿš‚","๐Ÿš†","๐Ÿš‡","๐ŸšŠ","๐Ÿš‰","โœˆ๏ธ","๐Ÿ›ซ","๐Ÿ›ฌ","๐Ÿ›ฉ","๐Ÿ’บ","๐Ÿ›ฐ","๐Ÿš€","๐Ÿ›ธ","๐Ÿš","๐Ÿ›ถ","โ›ต๏ธ","๐Ÿšค","๐Ÿ›ฅ","๐Ÿ›ณ","โ›ด","๐Ÿšข","โš“๏ธ","๐Ÿช","โ›ฝ๏ธ","๐Ÿšง","๐Ÿšฆ","๐Ÿšฅ","๐Ÿš","๐Ÿ—บ","๐Ÿ—ฟ","๐Ÿ—ฝ","๐Ÿ—ผ","๐Ÿฐ","๐Ÿฏ","๐ŸŸ","๐ŸŽก","๐ŸŽข","๐ŸŽ ","โ›ฒ๏ธ","โ›ฑ","๐Ÿ–","๐Ÿ","๐Ÿœ","๐ŸŒ‹","โ›ฐ","๐Ÿ”","๐Ÿ—ป","๐Ÿ•","โ›บ๏ธ","๐Ÿ›–","๐Ÿ ","๐Ÿก","๐Ÿ˜","๐Ÿš","๐Ÿ—","๐Ÿญ","๐Ÿข","๐Ÿฌ","๐Ÿฃ","๐Ÿค","๐Ÿฅ","๐Ÿฆ","๐Ÿจ","๐Ÿช","๐Ÿซ","๐Ÿฉ","๐Ÿ’’","๐Ÿ›","โ›ช๏ธ","๐Ÿ•Œ","๐Ÿ•","๐Ÿ›•","๐Ÿ•‹","โ›ฉ","๐Ÿ›ค","๐Ÿ›ฃ","๐Ÿ—พ","๐ŸŽ‘","๐Ÿž","๐ŸŒ…","๐ŸŒ„","๐ŸŒ ","๐ŸŽ‡","๐ŸŽ†","๐ŸŒ‡","๐ŸŒ†","๐Ÿ™","๐ŸŒƒ","๐ŸŒŒ","๐ŸŒ‰","๐ŸŒ" + + + +"โŒš๏ธ","๐Ÿ“ฑ","๐Ÿ“ฒ","๐Ÿ’ป","โŒจ๏ธ","๐Ÿ–ฅ","๐Ÿ–จ","๐Ÿ–ฑ","๐Ÿ–ฒ","๐Ÿ•น","๐Ÿ—œ","๐Ÿ’ฝ","๐Ÿ’พ","๐Ÿ’ฟ","๐Ÿ“€","๐Ÿ“ผ","๐Ÿ“ท","๐Ÿ“ธ","๐Ÿ“น","๐ŸŽฅ","๐Ÿ“ฝ","๐ŸŽž","๐Ÿ“ž","โ˜Ž๏ธ","๐Ÿ“Ÿ","๐Ÿ“ ","๐Ÿ“บ","๐Ÿ“ป","๐ŸŽ™","๐ŸŽš","๐ŸŽ›","๐Ÿงญ","โฑ","โฒ","โฐ","๐Ÿ•ฐ","โŒ›๏ธ","โณ","๐Ÿ“ก","๐Ÿ”‹","๐Ÿ”Œ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ•ฏ","๐Ÿช”","๐Ÿงฏ","๐Ÿ›ข","๐Ÿ’ธ","๐Ÿ’ต","๐Ÿ’ด","๐Ÿ’ถ","๐Ÿ’ท","๐Ÿช™","๐Ÿ’ฐ","๐Ÿ’ณ","๐Ÿ’Ž","โš–๏ธ","๐Ÿชœ","๐Ÿงฐ","๐Ÿช›","๐Ÿ”ง","๐Ÿ”จ","โš’","๐Ÿ› ","โ›","๐Ÿชš","๐Ÿ”ฉ","โš™๏ธ","๐Ÿชค","๐Ÿงฑ","โ›“","๐Ÿงฒ","๐Ÿ”ซ","๐Ÿ’ฃ","๐Ÿงจ","๐Ÿช“","๐Ÿ”ช","๐Ÿ—ก","โš”๏ธ","๐Ÿ›ก","๐Ÿšฌ","โšฐ๏ธ","๐Ÿชฆ","โšฑ๏ธ","๐Ÿบ","๐Ÿ”ฎ","๐Ÿ“ฟ","๐Ÿงฟ","๐Ÿ’ˆ","โš—๏ธ","๐Ÿ”ญ","๐Ÿ”ฌ","๐Ÿ•ณ","๐Ÿฉน","๐Ÿฉบ","๐Ÿ’Š","๐Ÿ’‰","๐Ÿฉธ","๐Ÿงฌ","๐Ÿฆ ","๐Ÿงซ","๐Ÿงช","๐ŸŒก","๐Ÿงน","๐Ÿช ","๐Ÿงบ","๐Ÿงป","๐Ÿšฝ","๐Ÿšฐ","๐Ÿšฟ","๐Ÿ›", +"๐Ÿ›€","๐Ÿ›€๐Ÿป","๐Ÿ›€๐Ÿผ","๐Ÿ›€๐Ÿฝ","๐Ÿ›€๐Ÿพ","๐Ÿ›€๐Ÿฟ", +"๐Ÿงผ","๐Ÿชฅ","๐Ÿช’","๐Ÿงฝ","๐Ÿชฃ","๐Ÿงด","๐Ÿ›Ž","๐Ÿ”‘","๐Ÿ—","๐Ÿšช","๐Ÿช‘","๐Ÿ›‹","๐Ÿ›","๐Ÿ›Œ","๐Ÿงธ","๐Ÿช†","๐Ÿ–ผ","๐Ÿชž","๐ŸชŸ","๐Ÿ›","๐Ÿ›’","๐ŸŽ","๐ŸŽˆ","๐ŸŽ","๐ŸŽ€","๐Ÿช„","๐Ÿช…","๐ŸŽŠ","๐ŸŽ‰","๐ŸŽŽ","๐Ÿฎ","๐ŸŽ","๐Ÿงง","โœ‰๏ธ","๐Ÿ“ฉ","๐Ÿ“จ","๐Ÿ“ง","๐Ÿ’Œ","๐Ÿ“ฅ","๐Ÿ“ค","๐Ÿ“ฆ","๐Ÿท","๐Ÿชง","๐Ÿ“ช","๐Ÿ“ซ","๐Ÿ“ฌ","๐Ÿ“ญ","๐Ÿ“ฎ","๐Ÿ“ฏ","๐Ÿ“œ","๐Ÿ“ƒ","๐Ÿ“„","๐Ÿ“‘","๐Ÿงพ","๐Ÿ“Š","๐Ÿ“ˆ","๐Ÿ“‰","๐Ÿ—’","๐Ÿ—“","๐Ÿ“†","๐Ÿ“…","๐Ÿ—‘","๐Ÿ“‡","๐Ÿ—ƒ","๐Ÿ—ณ","๐Ÿ—„","๐Ÿ“‹","๐Ÿ“","๐Ÿ“‚","๐Ÿ—‚","๐Ÿ—ž","๐Ÿ“ฐ","๐Ÿ““","๐Ÿ“”","๐Ÿ“’","๐Ÿ“•","๐Ÿ“—","๐Ÿ“˜","๐Ÿ“™","๐Ÿ“š","๐Ÿ“–","๐Ÿ”–","๐Ÿงท","๐Ÿ”—","๐Ÿ“Ž","๐Ÿ–‡","๐Ÿ“","๐Ÿ“","๐Ÿงฎ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ–Š","๐Ÿ–‹","โœ’๏ธ","๐Ÿ–Œ","๐Ÿ–","๐Ÿ“","โœ๏ธ","๐Ÿ”","๐Ÿ”Ž","๐Ÿ”","๐Ÿ”","๐Ÿ”’","๐Ÿ”“" + + + +"โค๏ธ","๐Ÿงก","๐Ÿ’›","๐Ÿ’š","๐Ÿ’™","๐Ÿ’œ","๐Ÿ–ค","๐Ÿค","๐ŸคŽ","๐Ÿ’”","โค๏ธโ€๐Ÿ”ฅ","โค๏ธโ€๐Ÿฉน","โฃ๏ธ","๐Ÿ’•","๐Ÿ’ž","๐Ÿ’“","๐Ÿ’—","๐Ÿ’–","๐Ÿ’˜","๐Ÿ’","๐Ÿ’Ÿ","โ˜ฎ๏ธ","โœ๏ธ","โ˜ช๏ธ","๐Ÿ•‰","โ˜ธ๏ธ","โœก๏ธ","๐Ÿ”ฏ","๐Ÿ•Ž","โ˜ฏ๏ธ","โ˜ฆ๏ธ","๐Ÿ›","โ›Ž","โ™ˆ๏ธ","โ™‰๏ธ","โ™Š๏ธ","โ™‹๏ธ","โ™Œ๏ธ","โ™๏ธ","โ™Ž๏ธ","โ™๏ธ","โ™๏ธ","โ™‘๏ธ","โ™’๏ธ","โ™“๏ธ","๐Ÿ†”","โš›๏ธ","๐Ÿ‰‘","โ˜ข๏ธ","โ˜ฃ๏ธ","๐Ÿ“ด","๐Ÿ“ณ","๐Ÿˆถ","๐Ÿˆš๏ธ","๐Ÿˆธ","๐Ÿˆบ","๐Ÿˆท๏ธ","โœด๏ธ","๐Ÿ†š","๐Ÿ’ฎ","๐Ÿ‰","ใŠ™๏ธ","ใŠ—๏ธ","๐Ÿˆด","๐Ÿˆต","๐Ÿˆน","๐Ÿˆฒ","๐Ÿ…ฐ๏ธ","๐Ÿ…ฑ๏ธ","๐Ÿ†Ž","๐Ÿ†‘","๐Ÿ…พ๏ธ","๐Ÿ†˜","โŒ","โญ•๏ธ","๐Ÿ›‘","โ›”๏ธ","๐Ÿ“›","๐Ÿšซ","๐Ÿ’ฏ","๐Ÿ’ข","โ™จ๏ธ","๐Ÿšท","๐Ÿšฏ","๐Ÿšณ","๐Ÿšฑ","๐Ÿ”ž","๐Ÿ“ต","๐Ÿšญ","โ—๏ธ","โ•","โ“","โ”","โ€ผ๏ธ","โ‰๏ธ","๐Ÿ”…","๐Ÿ”†","ใ€ฝ๏ธ","โš ๏ธ","๐Ÿšธ","๐Ÿ”ฑ","โšœ๏ธ","๐Ÿ”ฐ","โ™ป๏ธ","โœ…","๐Ÿˆฏ๏ธ","๐Ÿ’น","โ‡๏ธ","โœณ๏ธ","โŽ","๐ŸŒ","๐Ÿ’ ","โ“‚๏ธ","๐ŸŒ€","๐Ÿ’ค","๐Ÿง","๐Ÿšพ","โ™ฟ๏ธ","๐Ÿ…ฟ๏ธ","๐Ÿ›—","๐Ÿˆณ","๐Ÿˆ‚๏ธ","๐Ÿ›‚","๐Ÿ›ƒ","๐Ÿ›„","๐Ÿ›…","๐Ÿšน","๐Ÿšบ","๐Ÿšผ","โšง","๐Ÿšป","๐Ÿšฎ","๐ŸŽฆ","๐Ÿ“ถ","๐Ÿˆ","๐Ÿ”ฃ","โ„น๏ธ","๐Ÿ”ค","๐Ÿ”ก","๐Ÿ” ","๐Ÿ†–","๐Ÿ†—","๐Ÿ†™","๐Ÿ†’","๐Ÿ†•","๐Ÿ†“","0๏ธโƒฃ","1๏ธโƒฃ","2๏ธโƒฃ","3๏ธโƒฃ","4๏ธโƒฃ","5๏ธโƒฃ","6๏ธโƒฃ","7๏ธโƒฃ","8๏ธโƒฃ","9๏ธโƒฃ","๐Ÿ”Ÿ","๐Ÿ”ข","#๏ธโƒฃ","*๏ธโƒฃ","โ๏ธ","โ–ถ๏ธ","โธ","โฏ","โน","โบ","โญ","โฎ","โฉ","โช","โซ","โฌ","โ—€๏ธ","๐Ÿ”ผ","๐Ÿ”ฝ","โžก๏ธ","โฌ…๏ธ","โฌ†๏ธ","โฌ‡๏ธ","โ†—๏ธ","โ†˜๏ธ","โ†™๏ธ","โ†–๏ธ","โ†•๏ธ","โ†”๏ธ","โ†ช๏ธ","โ†ฉ๏ธ","โคด๏ธ","โคต๏ธ","๐Ÿ”€","๐Ÿ”","๐Ÿ”‚","๐Ÿ”„","๐Ÿ”ƒ","๐ŸŽต","๐ŸŽถ","โž•","โž–","โž—","โœ–๏ธ","โ™พ","๐Ÿ’ฒ","๐Ÿ’ฑ","โ„ข๏ธ","ยฉ๏ธ","ยฎ๏ธ","๐Ÿ‘โ€๐Ÿ—จ","๐Ÿ”š","๐Ÿ”™","๐Ÿ”›","๐Ÿ”","๐Ÿ”œ","ใ€ฐ๏ธ","โžฐ","โžฟ","โœ”๏ธ","โ˜‘๏ธ","๐Ÿ”˜","๐Ÿ”ด","๐ŸŸ ","๐ŸŸก","๐ŸŸข","๐Ÿ”ต","๐ŸŸฃ","โšซ๏ธ","โšช๏ธ","๐ŸŸค","๐Ÿ”บ","๐Ÿ”ป","๐Ÿ”ธ","๐Ÿ”น","๐Ÿ”ถ","๐Ÿ”ท","๐Ÿ”ณ","๐Ÿ”ฒ","โ–ช๏ธ","โ–ซ๏ธ","โ—พ๏ธ","โ—ฝ๏ธ","โ—ผ๏ธ","โ—ป๏ธ","๐ŸŸฅ","๐ŸŸง","๐ŸŸจ","๐ŸŸฉ","๐ŸŸฆ","๐ŸŸช","โฌ›๏ธ","โฌœ๏ธ","๐ŸŸซ","๐Ÿ”ˆ","๐Ÿ”‡","๐Ÿ”‰","๐Ÿ”Š","๐Ÿ””","๐Ÿ”•","๐Ÿ“ฃ","๐Ÿ“ข","๐Ÿ’ฌ","๐Ÿ’ญ","๐Ÿ—ฏ","โ™ ๏ธ","โ™ฃ๏ธ","โ™ฅ๏ธ","โ™ฆ๏ธ","๐Ÿƒ","๐ŸŽด","๐Ÿ€„๏ธ","๐Ÿ•","๐Ÿ•‘","๐Ÿ•’","๐Ÿ•“","๐Ÿ•”","๐Ÿ••","๐Ÿ•–","๐Ÿ•—","๐Ÿ•˜","๐Ÿ•™","๐Ÿ•š","๐Ÿ•›","๐Ÿ•œ","๐Ÿ•","๐Ÿ•ž","๐Ÿ•Ÿ","๐Ÿ• ","๐Ÿ•ก","๐Ÿ•ข","๐Ÿ•ฃ","๐Ÿ•ค","๐Ÿ•ฅ","๐Ÿ•ฆ","๐Ÿ•ง" + + +"๐Ÿณ๏ธ","๐Ÿด","๐Ÿดโ€โ˜ ๏ธ","๐Ÿ","๐Ÿšฉ","๐Ÿณ๏ธโ€๐ŸŒˆ","๐Ÿณ๏ธโ€โšง๏ธ","๐Ÿ‡บ๐Ÿ‡ณ","๐Ÿ‡ฆ๐Ÿ‡ซ","๐Ÿ‡ฆ๐Ÿ‡ฝ","๐Ÿ‡ฆ๐Ÿ‡ฑ","๐Ÿ‡ฉ๐Ÿ‡ฟ","๐Ÿ‡ฆ๐Ÿ‡ธ","๐Ÿ‡ฆ๐Ÿ‡ฉ","๐Ÿ‡ฆ๐Ÿ‡ด","๐Ÿ‡ฆ๐Ÿ‡ฎ","๐Ÿ‡ฆ๐Ÿ‡ถ","๐Ÿ‡ฆ๐Ÿ‡ฌ","๐Ÿ‡ฆ๐Ÿ‡ท","๐Ÿ‡ฆ๐Ÿ‡ฒ","๐Ÿ‡ฆ๐Ÿ‡ผ","๐Ÿ‡ฆ๐Ÿ‡บ","๐Ÿ‡ฆ๐Ÿ‡น","๐Ÿ‡ฆ๐Ÿ‡ฟ","๐Ÿ‡ง๐Ÿ‡ธ","๐Ÿ‡ง๐Ÿ‡ญ","๐Ÿ‡ง๐Ÿ‡ฉ","๐Ÿ‡ง๐Ÿ‡ง","๐Ÿ‡ง๐Ÿ‡พ","๐Ÿ‡ง๐Ÿ‡ช","๐Ÿ‡ง๐Ÿ‡ฟ","๐Ÿ‡ง๐Ÿ‡ฏ","๐Ÿ‡ง๐Ÿ‡ฒ","๐Ÿ‡ง๐Ÿ‡น","๐Ÿ‡ง๐Ÿ‡ด","๐Ÿ‡ง๐Ÿ‡ฆ","๐Ÿ‡ง๐Ÿ‡ผ","๐Ÿ‡ง๐Ÿ‡ท","๐Ÿ‡ป๐Ÿ‡ฌ","๐Ÿ‡ง๐Ÿ‡ณ","๐Ÿ‡ง๐Ÿ‡ฌ","๐Ÿ‡ง๐Ÿ‡ซ","๐Ÿ‡ง๐Ÿ‡ฎ","๐Ÿ‡ฐ๐Ÿ‡ญ","๐Ÿ‡จ๐Ÿ‡ฒ","๐Ÿ‡จ๐Ÿ‡ฆ","๐Ÿ‡ฎ๐Ÿ‡จ","๐Ÿ‡จ๐Ÿ‡ป","๐Ÿ‡ง๐Ÿ‡ถ","๐Ÿ‡ฐ๐Ÿ‡พ","๐Ÿ‡จ๐Ÿ‡ซ","๐Ÿ‡น๐Ÿ‡ฉ","๐Ÿ‡ฎ๐Ÿ‡ด","๐Ÿ‡จ๐Ÿ‡ฑ","๐Ÿ‡จ๐Ÿ‡ณ","๐Ÿ‡จ๐Ÿ‡ฝ","๐Ÿ‡จ๐Ÿ‡จ","๐Ÿ‡จ๐Ÿ‡ด","๐Ÿ‡ฐ๐Ÿ‡ฒ","๐Ÿ‡จ๐Ÿ‡ฌ","๐Ÿ‡จ๐Ÿ‡ฉ","๐Ÿ‡จ๐Ÿ‡ฐ","๐Ÿ‡จ๐Ÿ‡ท","๐Ÿ‡จ๐Ÿ‡ฎ","๐Ÿ‡ญ๐Ÿ‡ท","๐Ÿ‡จ๐Ÿ‡บ","๐Ÿ‡จ๐Ÿ‡ผ","๐Ÿ‡จ๐Ÿ‡พ","๐Ÿ‡จ๐Ÿ‡ฟ","๐Ÿ‡ฉ๐Ÿ‡ฐ","๐Ÿ‡ฉ๐Ÿ‡ฏ","๐Ÿ‡ฉ๐Ÿ‡ฒ","๐Ÿ‡ฉ๐Ÿ‡ด","๐Ÿ‡ช๐Ÿ‡จ","๐Ÿ‡ช๐Ÿ‡ฌ","๐Ÿ‡ธ๐Ÿ‡ป","๐Ÿ‡ฌ๐Ÿ‡ถ","๐Ÿ‡ช๐Ÿ‡ท","๐Ÿ‡ช๐Ÿ‡ช","๐Ÿ‡ธ๐Ÿ‡ฟ","๐Ÿ‡ช๐Ÿ‡น","๐Ÿ‡ช๐Ÿ‡บ","๐Ÿ‡ซ๐Ÿ‡ฐ","๐Ÿ‡ซ๐Ÿ‡ด","๐Ÿ‡ซ๐Ÿ‡ฏ","๐Ÿ‡ซ๐Ÿ‡ฎ","๐Ÿ‡ซ๐Ÿ‡ท","๐Ÿ‡ฌ๐Ÿ‡ซ","๐Ÿ‡ต๐Ÿ‡ซ","๐Ÿ‡น๐Ÿ‡ซ","๐Ÿ‡ฌ๐Ÿ‡ฆ","๐Ÿ‡ฌ๐Ÿ‡ฒ","๐Ÿ‡ฌ๐Ÿ‡ช","๐Ÿ‡ฉ๐Ÿ‡ช","๐Ÿ‡ฌ๐Ÿ‡ญ","๐Ÿ‡ฌ๐Ÿ‡ฎ","๐Ÿ‡ฌ๐Ÿ‡ท","๐Ÿ‡ฌ๐Ÿ‡ฑ","๐Ÿ‡ฌ๐Ÿ‡ฉ","๐Ÿ‡ฌ๐Ÿ‡ต","๐Ÿ‡ฌ๐Ÿ‡บ","๐Ÿ‡ฌ๐Ÿ‡น","๐Ÿ‡ฌ๐Ÿ‡ฌ","๐Ÿ‡ฌ๐Ÿ‡ณ","๐Ÿ‡ฌ๐Ÿ‡ผ","๐Ÿ‡ฌ๐Ÿ‡พ","๐Ÿ‡ญ๐Ÿ‡น","๐Ÿ‡ญ๐Ÿ‡ณ","๐Ÿ‡ญ๐Ÿ‡ฐ","๐Ÿ‡ญ๐Ÿ‡บ","๐Ÿ‡ฎ๐Ÿ‡ธ","๐Ÿ‡ฎ๐Ÿ‡ณ","๐Ÿ‡ฎ๐Ÿ‡ฉ","๐Ÿ‡ฎ๐Ÿ‡ท","๐Ÿ‡ฎ๐Ÿ‡ถ","๐Ÿ‡ฎ๐Ÿ‡ช","๐Ÿ‡ฎ๐Ÿ‡ฒ","๐Ÿ‡ฎ๐Ÿ‡ฑ","๐Ÿ‡ฎ๐Ÿ‡น","๐Ÿ‡ฏ๐Ÿ‡ฒ","๐Ÿ‡ฏ๐Ÿ‡ต","๐ŸŽŒ","๐Ÿ‡ฏ๐Ÿ‡ช","๐Ÿ‡ฏ๐Ÿ‡ด","๐Ÿ‡ฐ๐Ÿ‡ฟ","๐Ÿ‡ฐ๐Ÿ‡ช","๐Ÿ‡ฐ๐Ÿ‡ฎ","๐Ÿ‡ฝ๐Ÿ‡ฐ","๐Ÿ‡ฐ๐Ÿ‡ผ","๐Ÿ‡ฐ๐Ÿ‡ฌ","๐Ÿ‡ฑ๐Ÿ‡ฆ","๐Ÿ‡ฑ๐Ÿ‡ป","๐Ÿ‡ฑ๐Ÿ‡ง","๐Ÿ‡ฑ๐Ÿ‡ธ","๐Ÿ‡ฑ๐Ÿ‡ท","๐Ÿ‡ฑ๐Ÿ‡พ","๐Ÿ‡ฑ๐Ÿ‡ฎ","๐Ÿ‡ฑ๐Ÿ‡น","๐Ÿ‡ฑ๐Ÿ‡บ","๐Ÿ‡ฒ๐Ÿ‡ด","๐Ÿ‡ฒ๐Ÿ‡ฌ","๐Ÿ‡ฒ๐Ÿ‡ผ","๐Ÿ‡ฒ๐Ÿ‡พ","๐Ÿ‡ฒ๐Ÿ‡ป","๐Ÿ‡ฒ๐Ÿ‡ฑ","๐Ÿ‡ฒ๐Ÿ‡น","๐Ÿ‡ฒ๐Ÿ‡ญ","๐Ÿ‡ฒ๐Ÿ‡ถ","๐Ÿ‡ฒ๐Ÿ‡ท","๐Ÿ‡ฒ๐Ÿ‡บ","๐Ÿ‡พ๐Ÿ‡น","๐Ÿ‡ฒ๐Ÿ‡ฝ","๐Ÿ‡ซ๐Ÿ‡ฒ","๐Ÿ‡ฒ๐Ÿ‡ฉ","๐Ÿ‡ฒ๐Ÿ‡จ","๐Ÿ‡ฒ๐Ÿ‡ณ","๐Ÿ‡ฒ๐Ÿ‡ช","๐Ÿ‡ฒ๐Ÿ‡ธ","๐Ÿ‡ฒ๐Ÿ‡ฆ","๐Ÿ‡ฒ๐Ÿ‡ฟ","๐Ÿ‡ฒ๐Ÿ‡ฒ","๐Ÿ‡ณ๐Ÿ‡ฆ","๐Ÿ‡ณ๐Ÿ‡ท","๐Ÿ‡ณ๐Ÿ‡ต","๐Ÿ‡ณ๐Ÿ‡ฑ","๐Ÿ‡ณ๐Ÿ‡จ","๐Ÿ‡ณ๐Ÿ‡ฟ","๐Ÿ‡ณ๐Ÿ‡ฎ","๐Ÿ‡ณ๐Ÿ‡ช","๐Ÿ‡ณ๐Ÿ‡ฌ","๐Ÿ‡ณ๐Ÿ‡บ","๐Ÿ‡ณ๐Ÿ‡ซ","๐Ÿ‡ฐ๐Ÿ‡ต","๐Ÿ‡ฒ๐Ÿ‡ฐ","๐Ÿ‡ฒ๐Ÿ‡ต","๐Ÿ‡ณ๐Ÿ‡ด","๐Ÿ‡ด๐Ÿ‡ฒ","๐Ÿ‡ต๐Ÿ‡ฐ","๐Ÿ‡ต๐Ÿ‡ผ","๐Ÿ‡ต๐Ÿ‡ธ","๐Ÿ‡ต๐Ÿ‡ฆ","๐Ÿ‡ต๐Ÿ‡ฌ","๐Ÿ‡ต๐Ÿ‡พ","๐Ÿ‡ต๐Ÿ‡ช","๐Ÿ‡ต๐Ÿ‡ญ","๐Ÿ‡ต๐Ÿ‡ณ","๐Ÿ‡ต๐Ÿ‡ฑ","๐Ÿ‡ต๐Ÿ‡น","๐Ÿ‡ต๐Ÿ‡ท","๐Ÿ‡ถ๐Ÿ‡ฆ","๐Ÿ‡ท๐Ÿ‡ช","๐Ÿ‡ท๐Ÿ‡ด","๐Ÿ‡ท๐Ÿ‡บ","๐Ÿ‡ท๐Ÿ‡ผ","๐Ÿ‡ผ๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡ฒ","๐Ÿ‡ธ๐Ÿ‡น","๐Ÿ‡ธ๐Ÿ‡ฆ","๐Ÿ‡ธ๐Ÿ‡ณ","๐Ÿ‡ท๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡จ","๐Ÿ‡ธ๐Ÿ‡ฑ","๐Ÿ‡ธ๐Ÿ‡ฌ","๐Ÿ‡ธ๐Ÿ‡ฝ","๐Ÿ‡ธ๐Ÿ‡ฐ","๐Ÿ‡ธ๐Ÿ‡ฎ","๐Ÿ‡ฌ๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡ง","๐Ÿ‡ธ๐Ÿ‡ด","๐Ÿ‡ฟ๐Ÿ‡ฆ","๐Ÿ‡ฐ๐Ÿ‡ท","๐Ÿ‡ธ๐Ÿ‡ธ","๐Ÿ‡ช๐Ÿ‡ธ","๐Ÿ‡ฑ๐Ÿ‡ฐ","๐Ÿ‡ง๐Ÿ‡ฑ","๐Ÿ‡ธ๐Ÿ‡ญ","๐Ÿ‡ฐ๐Ÿ‡ณ","๐Ÿ‡ฑ๐Ÿ‡จ","๐Ÿ‡ต๐Ÿ‡ฒ","๐Ÿ‡ป๐Ÿ‡จ","๐Ÿ‡ธ๐Ÿ‡ฉ","๐Ÿ‡ธ๐Ÿ‡ท","๐Ÿ‡ธ๐Ÿ‡ช","๐Ÿ‡จ๐Ÿ‡ญ","๐Ÿ‡ธ๐Ÿ‡พ","๐Ÿ‡น๐Ÿ‡ผ","๐Ÿ‡น๐Ÿ‡ฏ","๐Ÿ‡น๐Ÿ‡ฟ","๐Ÿ‡น๐Ÿ‡ญ","๐Ÿ‡น๐Ÿ‡ฑ","๐Ÿ‡น๐Ÿ‡ฌ","๐Ÿ‡น๐Ÿ‡ฐ","๐Ÿ‡น๐Ÿ‡ด","๐Ÿ‡น๐Ÿ‡น","๐Ÿ‡น๐Ÿ‡ณ","๐Ÿ‡น๐Ÿ‡ท","๐Ÿ‡น๐Ÿ‡ฒ","๐Ÿ‡น๐Ÿ‡จ","๐Ÿ‡น๐Ÿ‡ป","๐Ÿ‡บ๐Ÿ‡ฌ","๐Ÿ‡บ๐Ÿ‡ฆ","๐Ÿ‡ฆ๐Ÿ‡ช","๐Ÿ‡ฌ๐Ÿ‡ง","๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ","๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ","๐Ÿด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ","๐Ÿ‡บ๐Ÿ‡ธ","๐Ÿ‡บ๐Ÿ‡พ","๐Ÿ‡ป๐Ÿ‡ฎ","๐Ÿ‡บ๐Ÿ‡ฟ","๐Ÿ‡ป๐Ÿ‡บ","๐Ÿ‡ป๐Ÿ‡ฆ","๐Ÿ‡ป๐Ÿ‡ช","๐Ÿ‡ป๐Ÿ‡ณ","๐Ÿ‡ผ๐Ÿ‡ซ","๐Ÿ‡ช๐Ÿ‡ญ","๐Ÿ‡พ๐Ÿ‡ช","๐Ÿ‡ฟ๐Ÿ‡ฒ","๐Ÿ‡ฟ๐Ÿ‡ผ" + + + + +========================================= + +"๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿ˜…","๐Ÿ˜‚","๐Ÿคฃ","๐Ÿฅฒ","โ˜บ๏ธ","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿ™‚","๐Ÿ™ƒ","๐Ÿ˜‰","๐Ÿ˜Œ","๐Ÿ˜","๐Ÿฅฐ","๐Ÿ˜˜","๐Ÿ˜—","๐Ÿ˜™","๐Ÿ˜š","๐Ÿ˜‹","๐Ÿ˜›","๐Ÿ˜","๐Ÿ˜œ","๐Ÿคช","๐Ÿคจ","๐Ÿง","๐Ÿค“","๐Ÿ˜Ž","๐Ÿฅธ","๐Ÿคฉ","๐Ÿฅณ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ˜ž","๐Ÿ˜”","๐Ÿ˜Ÿ","๐Ÿ˜•","๐Ÿ™","โ˜น๏ธ","๐Ÿ˜ฃ","๐Ÿ˜–","๐Ÿ˜ซ","๐Ÿ˜ฉ","๐Ÿฅบ","๐Ÿ˜ข","๐Ÿ˜ญ","๐Ÿ˜ค","๐Ÿ˜ ","๐Ÿ˜ก","๐Ÿคฌ","๐Ÿคฏ","๐Ÿ˜ณ","๐Ÿฅต","๐Ÿฅถ","๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿ˜ฑ","๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜“","๐Ÿค—","๐Ÿค”","๐Ÿคญ","๐Ÿคซ","๐Ÿคฅ","๐Ÿ˜ถ","๐Ÿ˜","๐Ÿ˜‘","๐Ÿ˜ฌ","๐Ÿ™„","๐Ÿ˜ฏ","๐Ÿ˜ฆ","๐Ÿ˜ง","๐Ÿ˜ฎ","๐Ÿ˜ฒ","๐Ÿฅฑ","๐Ÿ˜ด","๐Ÿคค","๐Ÿ˜ช","๐Ÿ˜ฎโ€๐Ÿ’จ","๐Ÿ˜ต","๐Ÿ˜ตโ€๐Ÿ’ซ","๐Ÿค","๐Ÿฅด","๐Ÿคข","๐Ÿคฎ","๐Ÿคง","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿค‘","๐Ÿค ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ‘น","๐Ÿ‘บ","๐Ÿคก","๐Ÿ’ฉ","๐Ÿ‘ป","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ‘ฝ","๐Ÿ‘พ","๐Ÿค–","๐ŸŽƒ","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น","๐Ÿ˜ป","๐Ÿ˜ผ","๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ", +"๐Ÿคฒ", +"๐Ÿ‘", +"๐Ÿ™Œ", +"๐Ÿ‘", +"๐Ÿค", +"๐Ÿ‘", +"๐Ÿ‘Ž", +"๐Ÿ‘Š", +"โœŠ", +"๐Ÿค›", +"๐Ÿคœ", +"๐Ÿคž", +"โœŒ๏ธ", +"๐ŸคŸ", +"๐Ÿค˜", +"๐Ÿ‘Œ", +"๐ŸคŒ", +"๐Ÿค", +"๐Ÿ‘ˆ", +"๐Ÿ‘‰", +"๐Ÿ‘†", +"๐Ÿ‘‡", +"โ˜๏ธ", +"โœ‹", +"๐Ÿคš", +"๐Ÿ–", +"๐Ÿ––", +"๐Ÿ‘‹", +"๐Ÿค™", +"๐Ÿ’ช", +"๐Ÿฆพ", +"๐Ÿ–•", +"โœ๏ธ", +"๐Ÿ™", +"๐Ÿฆถ", +"๐Ÿฆต", +"๐Ÿฆฟ","๐Ÿ’„","๐Ÿ’‹","๐Ÿ‘„","๐Ÿฆท","๐Ÿ‘…", +"๐Ÿ‘‚", +"๐Ÿฆป", +"๐Ÿ‘ƒ", +"๐Ÿ‘ฃ","๐Ÿ‘","๐Ÿ‘€","๐Ÿซ€","๐Ÿซ","๐Ÿง ","๐Ÿ—ฃ","๐Ÿ‘ค","๐Ÿ‘ฅ","๐Ÿซ‚", +"๐Ÿ‘ถ", +"๐Ÿ‘ง", +"๐Ÿง’", +"๐Ÿ‘ฆ", +"๐Ÿ‘ฉ", +"๐Ÿง‘", +"๐Ÿ‘จ", +"๐Ÿ‘ฉโ€๐Ÿฆฑ", +"๐Ÿง‘โ€๐Ÿฆฑ", +"๐Ÿ‘จโ€๐Ÿฆฑ", +"๐Ÿ‘ฉโ€๐Ÿฆฐ", +"๐Ÿง‘โ€๐Ÿฆฐ", +"๐Ÿ‘จโ€๐Ÿฆฐ", +"๐Ÿ‘ฑโ€โ™€๏ธ", +"๐Ÿ‘ฑ", +"๐Ÿ‘ฑโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€๐Ÿฆณ", +"๐Ÿง‘โ€๐Ÿฆณ", +"๐Ÿ‘จโ€๐Ÿฆณ", +"๐Ÿ‘ฉโ€๐Ÿฆฒ", +"๐Ÿง‘โ€๐Ÿฆฒ", +"๐Ÿ‘จโ€๐Ÿฆฒ", +"๐Ÿง”โ€โ™€๏ธ", +"๐Ÿง”", +"๐Ÿง”โ€โ™‚๏ธ", +"๐Ÿ‘ต", +"๐Ÿง“", +"๐Ÿ‘ด", +"๐Ÿ‘ฒ", +"๐Ÿ‘ณโ€โ™€๏ธ", +"๐Ÿ‘ณ", +"๐Ÿ‘ณโ€โ™‚๏ธ", +"๐Ÿง•", +"๐Ÿ‘ฎโ€โ™€๏ธ", +"๐Ÿ‘ฎ", +"๐Ÿ‘ฎโ€โ™‚๏ธ", +"๐Ÿ‘ทโ€โ™€๏ธ", +"๐Ÿ‘ท", +"๐Ÿ‘ทโ€โ™‚๏ธ", +"๐Ÿ’‚โ€โ™€๏ธ", +"๐Ÿ’‚", +"๐Ÿ’‚โ€โ™‚๏ธ", +"๐Ÿ•ต๏ธโ€โ™€๏ธ", +"๐Ÿ•ต๏ธ", +"๐Ÿ•ต๏ธโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€โš•๏ธ", +"๐Ÿง‘โ€โš•๏ธ", +"๐Ÿ‘จโ€โš•๏ธ", +"๐Ÿ‘ฉโ€๐ŸŒพ", +"๐Ÿง‘โ€๐ŸŒพ", +"๐Ÿ‘จโ€๐ŸŒพ", +"๐Ÿ‘ฉโ€๐Ÿณ", +"๐Ÿง‘โ€๐Ÿณ", +"๐Ÿ‘จโ€๐Ÿณ", +"๐Ÿ‘ฉโ€๐ŸŽ“", +"๐Ÿง‘โ€๐ŸŽ“", +"๐Ÿ‘จโ€๐ŸŽ“", +"๐Ÿ‘ฉโ€๐ŸŽค", +"๐Ÿง‘โ€๐ŸŽค", +"๐Ÿ‘จโ€๐ŸŽค", +"๐Ÿ‘ฉโ€๐Ÿซ", +"๐Ÿง‘โ€๐Ÿซ", +"๐Ÿ‘จโ€๐Ÿซ", +"๐Ÿ‘ฉโ€๐Ÿญ", +"๐Ÿง‘โ€๐Ÿญ", +"๐Ÿ‘จโ€๐Ÿญ", +"๐Ÿ‘ฉโ€๐Ÿ’ป", +"๐Ÿง‘โ€๐Ÿ’ป", +"๐Ÿ‘จโ€๐Ÿ’ป", +"๐Ÿ‘ฉโ€๐Ÿ’ผ", +"๐Ÿง‘โ€๐Ÿ’ผ", +"๐Ÿ‘จโ€๐Ÿ’ผ", +"๐Ÿ‘ฉโ€๐Ÿ”ง", +"๐Ÿง‘โ€๐Ÿ”ง", +"๐Ÿ‘จโ€๐Ÿ”ง", +"๐Ÿ‘ฉโ€๐Ÿ”ฌ", +"๐Ÿง‘โ€๐Ÿ”ฌ", +"๐Ÿ‘จโ€๐Ÿ”ฌ", +"๐Ÿ‘ฉโ€๐ŸŽจ", +"๐Ÿง‘โ€๐ŸŽจ", +"๐Ÿ‘จโ€๐ŸŽจ", +"๐Ÿ‘ฉโ€๐Ÿš’", +"๐Ÿง‘โ€๐Ÿš’", +"๐Ÿ‘จโ€๐Ÿš’", +"๐Ÿ‘ฉโ€โœˆ๏ธ", +"๐Ÿง‘โ€โœˆ๏ธ", +"๐Ÿ‘จโ€โœˆ๏ธ", +"๐Ÿ‘ฉโ€๐Ÿš€", +"๐Ÿง‘โ€๐Ÿš€", +"๐Ÿ‘จโ€๐Ÿš€", +"๐Ÿ‘ฉโ€โš–๏ธ", +"๐Ÿง‘โ€โš–๏ธ", +"๐Ÿ‘จโ€โš–๏ธ", +"๐Ÿ‘ฐโ€โ™€๏ธ", +"๐Ÿ‘ฐ", +"๐Ÿ‘ฐโ€โ™‚๏ธ", +"๐Ÿคตโ€โ™€๏ธ", +"๐Ÿคต", +"๐Ÿคตโ€โ™‚๏ธ", +"๐Ÿ‘ธ", +"๐Ÿคด", +"๐Ÿฅท", +"๐Ÿฆธโ€โ™€๏ธ", +"๐Ÿฆธ", +"๐Ÿฆธโ€โ™‚๏ธ", +"๐Ÿฆนโ€โ™€๏ธ", +"๐Ÿฆน", +"๐Ÿฆนโ€โ™‚๏ธ", +"๐Ÿคถ", +"๐Ÿง‘โ€๐ŸŽ„", +"๐ŸŽ…", +"๐Ÿง™โ€โ™€๏ธ", +"๐Ÿง™", +"๐Ÿง™โ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ", +"๐Ÿง", +"๐Ÿงโ€โ™‚๏ธ", +"๐Ÿง›โ€โ™€๏ธ", +"๐Ÿง›", +"๐Ÿง›โ€โ™‚๏ธ", +"๐ŸงŸโ€โ™€๏ธ","๐ŸงŸ","๐ŸงŸโ€โ™‚๏ธ","๐Ÿงžโ€โ™€๏ธ","๐Ÿงž","๐Ÿงžโ€โ™‚๏ธ", +"๐Ÿงœโ€โ™€๏ธ", +"๐Ÿงœ", +"๐Ÿงœโ€โ™‚๏ธ", +"๐Ÿงšโ€โ™€๏ธ", +"๐Ÿงš", +"๐Ÿงšโ€โ™‚๏ธ", +"๐Ÿ‘ผ", +"๐Ÿคฐ", +"๐Ÿคฑ", +"๐Ÿ‘ฉโ€๐Ÿผ", +"๐Ÿง‘โ€๐Ÿผ", +"๐Ÿ‘จโ€๐Ÿผ", +"๐Ÿ™‡โ€โ™€๏ธ", +"๐Ÿ™‡", +"๐Ÿ™‡โ€โ™‚๏ธ", +"๐Ÿ’โ€โ™€๏ธ", +"๐Ÿ’", +"๐Ÿ’โ€โ™‚๏ธ", +"๐Ÿ™…โ€โ™€๏ธ", +"๐Ÿ™…", +"๐Ÿ™…โ€โ™‚๏ธ", +"๐Ÿ™†โ€โ™€๏ธ", +"๐Ÿ™†", +"๐Ÿ™†โ€โ™‚๏ธ", +"๐Ÿ™‹โ€โ™€๏ธ", +"๐Ÿ™‹", +"๐Ÿ™‹โ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ", +"๐Ÿง", +"๐Ÿงโ€โ™‚๏ธ", +"๐Ÿคฆโ€โ™€๏ธ", +"๐Ÿคฆ", +"๐Ÿคฆโ€โ™‚๏ธ", +"๐Ÿคทโ€โ™€๏ธ", +"๐Ÿคท", +"๐Ÿคทโ€โ™‚๏ธ", +"๐Ÿ™Žโ€โ™€๏ธ", +"๐Ÿ™Ž", +"๐Ÿ™Žโ€โ™‚๏ธ", +"๐Ÿ™โ€โ™€๏ธ", +"๐Ÿ™", +"๐Ÿ™โ€โ™‚๏ธ", +"๐Ÿ’‡โ€โ™€๏ธ", +"๐Ÿ’‡", +"๐Ÿ’‡โ€โ™‚๏ธ", +"๐Ÿ’†โ€โ™€๏ธ", +"๐Ÿ’†", +"๐Ÿ’†โ€โ™‚๏ธ", +"๐Ÿง–โ€โ™€๏ธ", +"๐Ÿง–", +"๐Ÿง–โ€โ™‚๏ธ", +"๐Ÿ’…", +"๐Ÿคณ", +"๐Ÿ’ƒ", +"๐Ÿ•บ", +"๐Ÿ‘ฏโ€โ™€๏ธ","๐Ÿ‘ฏ","๐Ÿ‘ฏโ€โ™‚๏ธ", +"๐Ÿ•ด", +"๐Ÿ‘ฉโ€๐Ÿฆฝ", +"๐Ÿง‘โ€๐Ÿฆฝ", +"๐Ÿ‘จโ€๐Ÿฆฝ", +"๐Ÿ‘ฉโ€๐Ÿฆผ", +"๐Ÿง‘โ€๐Ÿฆผ", +"๐Ÿ‘จโ€๐Ÿฆผ", +"๐Ÿšถโ€โ™€๏ธ", +"๐Ÿšถ", +"๐Ÿšถโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€๐Ÿฆฏ", +"๐Ÿง‘โ€๐Ÿฆฏ", +"๐Ÿ‘จโ€๐Ÿฆฏ", +"๐ŸงŽโ€โ™€๏ธ", +"๐ŸงŽ", +"๐ŸงŽโ€โ™‚๏ธ", +"๐Ÿƒโ€โ™€๏ธ", +"๐Ÿƒ", +"๐Ÿƒโ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ", +"๐Ÿง", +"๐Ÿงโ€โ™‚๏ธ", +"๐Ÿ‘ซ", +"๐Ÿ‘ญ", +"๐Ÿ‘ฌ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ", +"๐Ÿ’‘", +"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ", +"๐Ÿ’", +"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", +"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿชข","๐Ÿงถ","๐Ÿงต","๐Ÿชก","๐Ÿงฅ","๐Ÿฅผ","๐Ÿฆบ","๐Ÿ‘š","๐Ÿ‘•","๐Ÿ‘–","๐Ÿฉฒ","๐Ÿฉณ","๐Ÿ‘”","๐Ÿ‘—","๐Ÿ‘™","๐Ÿฉฑ","๐Ÿ‘˜","๐Ÿฅป","๐Ÿฉด","๐Ÿฅฟ","๐Ÿ‘ ","๐Ÿ‘ก","๐Ÿ‘ข","๐Ÿ‘ž","๐Ÿ‘Ÿ","๐Ÿฅพ","๐Ÿงฆ","๐Ÿงค","๐Ÿงฃ","๐ŸŽฉ","๐Ÿงข","๐Ÿ‘’","๐ŸŽ“","โ›‘","๐Ÿช–","๐Ÿ‘‘","๐Ÿ’","๐Ÿ‘","๐Ÿ‘›","๐Ÿ‘œ","๐Ÿ’ผ","๐ŸŽ’","๐Ÿงณ","๐Ÿ‘“","๐Ÿ•ถ","๐Ÿฅฝ","๐ŸŒ‚" + + +"โšฝ๏ธ","๐Ÿ€","๐Ÿˆ","โšพ๏ธ","๐ŸฅŽ","๐ŸŽพ","๐Ÿ","๐Ÿ‰","๐Ÿฅ","๐ŸŽฑ","๐Ÿช€","๐Ÿ“","๐Ÿธ","๐Ÿ’","๐Ÿ‘","๐Ÿฅ","๐Ÿ","๐Ÿชƒ","๐Ÿฅ…","โ›ณ๏ธ","๐Ÿช","๐Ÿน","๐ŸŽฃ","๐Ÿคฟ","๐ŸฅŠ","๐Ÿฅ‹","๐ŸŽฝ","๐Ÿ›น","๐Ÿ›ผ","๐Ÿ›ท","โ›ธ","๐ŸฅŒ","๐ŸŽฟ","โ›ท","๐Ÿ‚","๐Ÿช‚", +"๐Ÿ‹๏ธโ€โ™€๏ธ", +"๐Ÿ‹๏ธ", +"๐Ÿ‹๏ธโ€โ™‚๏ธ", +"๐Ÿคผโ€โ™€๏ธ","๐Ÿคผ","๐Ÿคผโ€โ™‚๏ธ", +"๐Ÿคธโ€โ™€๏ธ", +"๐Ÿคธ", +"๐Ÿคธโ€โ™‚๏ธ", +"โ›น๏ธโ€โ™€๏ธ", +"โ›น๏ธ", +"โ›น๏ธโ€โ™‚๏ธ", +"๐Ÿคบ", +"๐Ÿคพโ€โ™€๏ธ", +"๐Ÿคพ", +"๐Ÿคพโ€โ™‚๏ธ", +"๐ŸŒ๏ธโ€โ™€๏ธ", +"๐ŸŒ๏ธ", +"๐ŸŒ๏ธโ€โ™‚๏ธ", +"๐Ÿ‡", +"๐Ÿง˜โ€โ™€๏ธ", +"๐Ÿง˜", +"๐Ÿง˜โ€โ™‚๏ธ", +"๐Ÿ„โ€โ™€๏ธ", +"๐Ÿ„", +"๐Ÿ„โ€โ™‚๏ธ", +"๐ŸŠโ€โ™€๏ธ", +"๐ŸŠ", +"๐ŸŠโ€โ™‚๏ธ", +"๐Ÿคฝโ€โ™€๏ธ", +"๐Ÿคฝ", +"๐Ÿคฝโ€โ™‚๏ธ", +"๐Ÿšฃโ€โ™€๏ธ", +"๐Ÿšฃ", +"๐Ÿšฃโ€โ™‚๏ธ", +"๐Ÿง—โ€โ™€๏ธ", +"๐Ÿง—", +"๐Ÿง—โ€โ™‚๏ธ", +"๐Ÿšตโ€โ™€๏ธ", +"๐Ÿšต", +"๐Ÿšตโ€โ™‚๏ธ", +"๐Ÿšดโ€โ™€๏ธ", +"๐Ÿšด", +"๐Ÿšดโ€โ™‚๏ธ", +"๐Ÿ†","๐Ÿฅ‡","๐Ÿฅˆ","๐Ÿฅ‰","๐Ÿ…","๐ŸŽ–","๐Ÿต","๐ŸŽ—","๐ŸŽซ","๐ŸŽŸ","๐ŸŽช", +"๐Ÿคนโ€โ™€๏ธ", +"๐Ÿคน", +"๐Ÿคนโ€โ™‚๏ธ", +"๐ŸŽญ","๐Ÿฉฐ","๐ŸŽจ","๐ŸŽฌ","๐ŸŽค","๐ŸŽง","๐ŸŽผ","๐ŸŽน","๐Ÿฅ","๐Ÿช˜","๐ŸŽท","๐ŸŽบ","๐Ÿช—","๐ŸŽธ","๐Ÿช•","๐ŸŽป","๐ŸŽฒ","โ™Ÿ","๐ŸŽฏ","๐ŸŽณ","๐ŸŽฎ","๐ŸŽฐ","๐Ÿงฉ" + + + + +"โŒš๏ธ","๐Ÿ“ฑ","๐Ÿ“ฒ","๐Ÿ’ป","โŒจ๏ธ","๐Ÿ–ฅ","๐Ÿ–จ","๐Ÿ–ฑ","๐Ÿ–ฒ","๐Ÿ•น","๐Ÿ—œ","๐Ÿ’ฝ","๐Ÿ’พ","๐Ÿ’ฟ","๐Ÿ“€","๐Ÿ“ผ","๐Ÿ“ท","๐Ÿ“ธ","๐Ÿ“น","๐ŸŽฅ","๐Ÿ“ฝ","๐ŸŽž","๐Ÿ“ž","โ˜Ž๏ธ","๐Ÿ“Ÿ","๐Ÿ“ ","๐Ÿ“บ","๐Ÿ“ป","๐ŸŽ™","๐ŸŽš","๐ŸŽ›","๐Ÿงญ","โฑ","โฒ","โฐ","๐Ÿ•ฐ","โŒ›๏ธ","โณ","๐Ÿ“ก","๐Ÿ”‹","๐Ÿ”Œ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ•ฏ","๐Ÿช”","๐Ÿงฏ","๐Ÿ›ข","๐Ÿ’ธ","๐Ÿ’ต","๐Ÿ’ด","๐Ÿ’ถ","๐Ÿ’ท","๐Ÿช™","๐Ÿ’ฐ","๐Ÿ’ณ","๐Ÿ’Ž","โš–๏ธ","๐Ÿชœ","๐Ÿงฐ","๐Ÿช›","๐Ÿ”ง","๐Ÿ”จ","โš’","๐Ÿ› ","โ›","๐Ÿชš","๐Ÿ”ฉ","โš™๏ธ","๐Ÿชค","๐Ÿงฑ","โ›“","๐Ÿงฒ","๐Ÿ”ซ","๐Ÿ’ฃ","๐Ÿงจ","๐Ÿช“","๐Ÿ”ช","๐Ÿ—ก","โš”๏ธ","๐Ÿ›ก","๐Ÿšฌ","โšฐ๏ธ","๐Ÿชฆ","โšฑ๏ธ","๐Ÿบ","๐Ÿ”ฎ","๐Ÿ“ฟ","๐Ÿงฟ","๐Ÿ’ˆ","โš—๏ธ","๐Ÿ”ญ","๐Ÿ”ฌ","๐Ÿ•ณ","๐Ÿฉน","๐Ÿฉบ","๐Ÿ’Š","๐Ÿ’‰","๐Ÿฉธ","๐Ÿงฌ","๐Ÿฆ ","๐Ÿงซ","๐Ÿงช","๐ŸŒก","๐Ÿงน","๐Ÿช ","๐Ÿงบ","๐Ÿงป","๐Ÿšฝ","๐Ÿšฐ","๐Ÿšฟ","๐Ÿ›", +"๐Ÿ›€", +"๐Ÿงผ","๐Ÿชฅ","๐Ÿช’","๐Ÿงฝ","๐Ÿชฃ","๐Ÿงด","๐Ÿ›Ž","๐Ÿ”‘","๐Ÿ—","๐Ÿšช","๐Ÿช‘","๐Ÿ›‹","๐Ÿ›","๐Ÿ›Œ","๐Ÿงธ","๐Ÿช†","๐Ÿ–ผ","๐Ÿชž","๐ŸชŸ","๐Ÿ›","๐Ÿ›’","๐ŸŽ","๐ŸŽˆ","๐ŸŽ","๐ŸŽ€","๐Ÿช„","๐Ÿช…","๐ŸŽŠ","๐ŸŽ‰","๐ŸŽŽ","๐Ÿฎ","๐ŸŽ","๐Ÿงง","โœ‰๏ธ","๐Ÿ“ฉ","๐Ÿ“จ","๐Ÿ“ง","๐Ÿ’Œ","๐Ÿ“ฅ","๐Ÿ“ค","๐Ÿ“ฆ","๐Ÿท","๐Ÿชง","๐Ÿ“ช","๐Ÿ“ซ","๐Ÿ“ฌ","๐Ÿ“ญ","๐Ÿ“ฎ","๐Ÿ“ฏ","๐Ÿ“œ","๐Ÿ“ƒ","๐Ÿ“„","๐Ÿ“‘","๐Ÿงพ","๐Ÿ“Š","๐Ÿ“ˆ","๐Ÿ“‰","๐Ÿ—’","๐Ÿ—“","๐Ÿ“†","๐Ÿ“…","๐Ÿ—‘","๐Ÿ“‡","๐Ÿ—ƒ","๐Ÿ—ณ","๐Ÿ—„","๐Ÿ“‹","๐Ÿ“","๐Ÿ“‚","๐Ÿ—‚","๐Ÿ—ž","๐Ÿ“ฐ","๐Ÿ““","๐Ÿ“”","๐Ÿ“’","๐Ÿ“•","๐Ÿ“—","๐Ÿ“˜","๐Ÿ“™","๐Ÿ“š","๐Ÿ“–","๐Ÿ”–","๐Ÿงท","๐Ÿ”—","๐Ÿ“Ž","๐Ÿ–‡","๐Ÿ“","๐Ÿ“","๐Ÿงฎ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ–Š","๐Ÿ–‹","โœ’๏ธ","๐Ÿ–Œ","๐Ÿ–","๐Ÿ“","โœ๏ธ","๐Ÿ”","๐Ÿ”Ž","๐Ÿ”","๐Ÿ”","๐Ÿ”’","๐Ÿ”“" + + + +========================================= +"๐Ÿคฒ","๐Ÿ‘","๐Ÿ™Œ","๐Ÿ‘","๐Ÿ‘","๐Ÿ‘Ž","๐Ÿ‘Š","โœŠ","๐Ÿค›","๐Ÿคœ","๐Ÿคž","โœŒ๏ธ","๐ŸคŸ","๐Ÿค˜","๐Ÿ‘Œ","๐ŸคŒ","๐Ÿค","๐Ÿ‘ˆ","๐Ÿ‘‰","๐Ÿ‘†","๐Ÿ‘‡","โ˜๏ธ","โœ‹","๐Ÿคš","๐Ÿ–","๐Ÿ––","๐Ÿ‘‹","๐Ÿค™","๐Ÿ’ช","๐Ÿ–•","โœ๏ธ","๐Ÿ™","๐Ÿฆถ","๐Ÿฆต","๐Ÿ‘‚","๐Ÿฆป","๐Ÿ‘ƒ","๐Ÿ‘ถ","๐Ÿ‘ง","๐Ÿง’","๐Ÿ‘ฆ","๐Ÿ‘ฉ","๐Ÿง‘","๐Ÿ‘จ","๐Ÿ‘ฉโ€๐Ÿฆฑ","๐Ÿง‘โ€๐Ÿฆฑ","๐Ÿ‘จโ€๐Ÿฆฑ","๐Ÿ‘ฉโ€๐Ÿฆฐ","๐Ÿง‘โ€๐Ÿฆฐ","๐Ÿ‘จโ€๐Ÿฆฐ","๐Ÿ‘ฑโ€โ™€๏ธ","๐Ÿ‘ฑ","๐Ÿ‘ฑโ€โ™‚๏ธ","๐Ÿ‘ฉโ€๐Ÿฆณ","๐Ÿง‘โ€๐Ÿฆณ","๐Ÿ‘จโ€๐Ÿฆณ","๐Ÿ‘ฉโ€๐Ÿฆฒ","๐Ÿง‘โ€๐Ÿฆฒ","๐Ÿ‘จโ€๐Ÿฆฒ","๐Ÿง”โ€โ™€๏ธ","๐Ÿง”","๐Ÿง”โ€โ™‚๏ธ","๐Ÿ‘ต","๐Ÿง“","๐Ÿ‘ด","๐Ÿ‘ฒ","๐Ÿ‘ณโ€โ™€๏ธ","๐Ÿ‘ณ","๐Ÿ‘ณโ€โ™‚๏ธ","๐Ÿง•","๐Ÿ‘ฎโ€โ™€๏ธ","๐Ÿ‘ฎ","๐Ÿ‘ฎโ€โ™‚๏ธ","๐Ÿ‘ทโ€โ™€๏ธ","๐Ÿ‘ท","๐Ÿ‘ทโ€โ™‚๏ธ","๐Ÿ’‚โ€โ™€๏ธ","๐Ÿ’‚","๐Ÿ’‚โ€โ™‚๏ธ","๐Ÿ•ต๏ธโ€โ™€๏ธ","๐Ÿ•ต๏ธ","๐Ÿ•ต๏ธโ€โ™‚๏ธ","๐Ÿ‘ฉโ€โš•๏ธ","๐Ÿง‘โ€โš•๏ธ","๐Ÿ‘จโ€โš•๏ธ","๐Ÿ‘ฉโ€๐ŸŒพ","๐Ÿง‘โ€๐ŸŒพ","๐Ÿ‘จโ€๐ŸŒพ","๐Ÿ‘ฉโ€๐Ÿณ","๐Ÿง‘โ€๐Ÿณ","๐Ÿ‘จโ€๐Ÿณ","๐Ÿ‘ฉโ€๐ŸŽ“","๐Ÿง‘โ€๐ŸŽ“","๐Ÿ‘จโ€๐ŸŽ“","๐Ÿ‘ฉโ€๐ŸŽค","๐Ÿง‘โ€๐ŸŽค","๐Ÿ‘จโ€๐ŸŽค","๐Ÿ‘ฉโ€๐Ÿซ","๐Ÿง‘โ€๐Ÿซ","๐Ÿ‘จโ€๐Ÿซ","๐Ÿ‘ฉโ€๐Ÿญ","๐Ÿง‘โ€๐Ÿญ","๐Ÿ‘จโ€๐Ÿญ","๐Ÿ‘ฉโ€๐Ÿ’ป","๐Ÿง‘โ€๐Ÿ’ป","๐Ÿ‘จโ€๐Ÿ’ป","๐Ÿ‘ฉโ€๐Ÿ’ผ","๐Ÿง‘โ€๐Ÿ’ผ","๐Ÿ‘จโ€๐Ÿ’ผ","๐Ÿ‘ฉโ€๐Ÿ”ง","๐Ÿง‘โ€๐Ÿ”ง","๐Ÿ‘จโ€๐Ÿ”ง","๐Ÿ‘ฉโ€๐Ÿ”ฌ","๐Ÿง‘โ€๐Ÿ”ฌ","๐Ÿ‘จโ€๐Ÿ”ฌ","๐Ÿ‘ฉโ€๐ŸŽจ","๐Ÿง‘โ€๐ŸŽจ","๐Ÿ‘จโ€๐ŸŽจ","๐Ÿ‘ฉโ€๐Ÿš’","๐Ÿง‘โ€๐Ÿš’","๐Ÿ‘จโ€๐Ÿš’","๐Ÿ‘ฉโ€โœˆ๏ธ","๐Ÿง‘โ€โœˆ๏ธ","๐Ÿ‘จโ€โœˆ๏ธ","๐Ÿ‘ฉโ€๐Ÿš€","๐Ÿง‘โ€๐Ÿš€","๐Ÿ‘จโ€๐Ÿš€","๐Ÿ‘ฉโ€โš–๏ธ","๐Ÿง‘โ€โš–๏ธ","๐Ÿ‘จโ€โš–๏ธ","๐Ÿ‘ฐโ€โ™€๏ธ","๐Ÿ‘ฐ","๐Ÿ‘ฐโ€โ™‚๏ธ","๐Ÿคตโ€โ™€๏ธ","๐Ÿคต","๐Ÿคตโ€โ™‚๏ธ","๐Ÿ‘ธ","๐Ÿคด","๐Ÿฅท","๐Ÿฆธโ€โ™€๏ธ","๐Ÿฆธ","๐Ÿฆธโ€โ™‚๏ธ","๐Ÿฆนโ€โ™€๏ธ","๐Ÿฆน","๐Ÿฆนโ€โ™‚๏ธ","๐Ÿคถ","๐Ÿง‘โ€๐ŸŽ„","๐ŸŽ…","๐Ÿง™โ€โ™€๏ธ","๐Ÿง™","๐Ÿง™โ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿง›โ€โ™€๏ธ","๐Ÿง›","๐Ÿง›โ€โ™‚๏ธ","๐Ÿงœโ€โ™€๏ธ","๐Ÿงœ","๐Ÿงœโ€โ™‚๏ธ","๐Ÿงšโ€โ™€๏ธ","๐Ÿงš","๐Ÿงšโ€โ™‚๏ธ","๐Ÿ‘ผ","๐Ÿคฐ","๐Ÿคฑ","๐Ÿ‘ฉโ€๐Ÿผ","๐Ÿง‘โ€๐Ÿผ","๐Ÿ‘จโ€๐Ÿผ","๐Ÿ™‡โ€โ™€๏ธ","๐Ÿ™‡","๐Ÿ™‡โ€โ™‚๏ธ","๐Ÿ’โ€โ™€๏ธ","๐Ÿ’","๐Ÿ’โ€โ™‚๏ธ","๐Ÿ™…โ€โ™€๏ธ","๐Ÿ™…","๐Ÿ™…โ€โ™‚๏ธ","๐Ÿ™†โ€โ™€๏ธ","๐Ÿ™†","๐Ÿ™†โ€โ™‚๏ธ","๐Ÿ™‹โ€โ™€๏ธ","๐Ÿ™‹","๐Ÿ™‹โ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿคฆโ€โ™€๏ธ","๐Ÿคฆ","๐Ÿคฆโ€โ™‚๏ธ","๐Ÿคทโ€โ™€๏ธ","๐Ÿคท","๐Ÿคทโ€โ™‚๏ธ","๐Ÿ™Žโ€โ™€๏ธ","๐Ÿ™Ž","๐Ÿ™Žโ€โ™‚๏ธ","๐Ÿ™โ€โ™€๏ธ","๐Ÿ™","๐Ÿ™โ€โ™‚๏ธ","๐Ÿ’‡โ€โ™€๏ธ","๐Ÿ’‡","๐Ÿ’‡โ€โ™‚๏ธ","๐Ÿ’†โ€โ™€๏ธ","๐Ÿ’†","๐Ÿ’†โ€โ™‚๏ธ","๐Ÿง–โ€โ™€๏ธ","๐Ÿง–","๐Ÿง–โ€โ™‚๏ธ","๐Ÿ’…","๐Ÿคณ","๐Ÿ’ƒ","๐Ÿ•บ","๐Ÿ•ด","๐Ÿ‘ฉโ€๐Ÿฆฝ","๐Ÿง‘โ€๐Ÿฆฝ","๐Ÿ‘จโ€๐Ÿฆฝ","๐Ÿ‘ฉโ€๐Ÿฆผ","๐Ÿง‘โ€๐Ÿฆผ","๐Ÿ‘จโ€๐Ÿฆผ","๐Ÿšถโ€โ™€๏ธ","๐Ÿšถ","๐Ÿšถโ€โ™‚๏ธ","๐Ÿ‘ฉโ€๐Ÿฆฏ","๐Ÿง‘โ€๐Ÿฆฏ","๐Ÿ‘จโ€๐Ÿฆฏ","๐ŸงŽโ€โ™€๏ธ","๐ŸงŽ","๐ŸงŽโ€โ™‚๏ธ","๐Ÿƒโ€โ™€๏ธ","๐Ÿƒ","๐Ÿƒโ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿ‹๏ธโ€โ™€๏ธ","๐Ÿ‹๏ธ","๐Ÿ‹๏ธโ€โ™‚๏ธ","๐Ÿคธโ€โ™€๏ธ","๐Ÿคธ","๐Ÿคธโ€โ™‚๏ธ","โ›น๏ธโ€โ™€๏ธ","โ›น๏ธ","โ›น๏ธโ€โ™‚๏ธ","๐Ÿคพโ€โ™€๏ธ","๐Ÿคพ","๐Ÿคพโ€โ™‚๏ธ","๐ŸŒ๏ธโ€โ™€๏ธ","๐ŸŒ๏ธ","๐ŸŒ๏ธโ€โ™‚๏ธ","๐Ÿ‡","๐Ÿง˜โ€โ™€๏ธ","๐Ÿง˜","๐Ÿง˜โ€โ™‚๏ธ","๐Ÿ„โ€โ™€๏ธ","๐Ÿ„","๐Ÿ„โ€โ™‚๏ธ","๐ŸŠโ€โ™€๏ธ","๐ŸŠ","๐ŸŠโ€โ™‚๏ธ","๐Ÿคฝโ€โ™€๏ธ","๐Ÿคฝ","๐Ÿคฝโ€โ™‚๏ธ","๐Ÿšฃโ€โ™€๏ธ","๐Ÿšฃ","๐Ÿšฃโ€โ™‚๏ธ","๐Ÿง—โ€โ™€๏ธ","๐Ÿง—","๐Ÿง—โ€โ™‚๏ธ","๐Ÿšตโ€โ™€๏ธ","๐Ÿšต","๐Ÿšตโ€โ™‚๏ธ","๐Ÿšดโ€โ™€๏ธ","๐Ÿšด","๐Ÿšดโ€โ™‚๏ธ","๐Ÿคนโ€โ™€๏ธ","๐Ÿคน","๐Ÿคนโ€โ™‚๏ธ","๐Ÿ›€" + + +"๐Ÿ‘ซ","๐Ÿ‘ญ","๐Ÿ‘ฌ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ","๐Ÿ’‘","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ","๐Ÿ’","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ" + +========================================= + + +"๐Ÿ—จ", "๐Ÿ‘ช" diff --git a/emoji_old/data5.txt b/emoji_old/data5.txt new file mode 100644 index 0000000..05755f1 --- /dev/null +++ b/emoji_old/data5.txt @@ -0,0 +1,676 @@ +"๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿฅน","๐Ÿ˜…","๐Ÿ˜‚","๐Ÿคฃ","๐Ÿฅฒ","โ˜บ๏ธ","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿ™‚","๐Ÿ™ƒ","๐Ÿ˜‰","๐Ÿ˜Œ","๐Ÿ˜","๐Ÿฅฐ","๐Ÿ˜˜","๐Ÿ˜—","๐Ÿ˜™","๐Ÿ˜š","๐Ÿ˜‹","๐Ÿ˜›","๐Ÿ˜","๐Ÿ˜œ","๐Ÿคช","๐Ÿคจ","๐Ÿง","๐Ÿค“","๐Ÿ˜Ž","๐Ÿฅธ","๐Ÿคฉ","๐Ÿฅณ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ˜ž","๐Ÿ˜”","๐Ÿ˜Ÿ","๐Ÿ˜•","๐Ÿ™","โ˜น๏ธ","๐Ÿ˜ฃ","๐Ÿ˜–","๐Ÿ˜ซ","๐Ÿ˜ฉ","๐Ÿฅบ","๐Ÿ˜ข","๐Ÿ˜ญ","๐Ÿ˜ค","๐Ÿ˜ ","๐Ÿ˜ก","๐Ÿคฌ","๐Ÿคฏ","๐Ÿ˜ณ","๐Ÿฅต","๐Ÿฅถ","๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿ˜ฑ","๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜“","๐Ÿค—","๐Ÿค”","๐Ÿซฃ","๐Ÿคญ","๐Ÿซข","๐Ÿซก","๐Ÿคซ","๐Ÿซ ","๐Ÿคฅ","๐Ÿ˜ถ","๐Ÿซฅ","๐Ÿ˜","๐Ÿซค","๐Ÿ˜‘","๐Ÿ˜ฌ","๐Ÿ™„","๐Ÿ˜ฏ","๐Ÿ˜ฆ","๐Ÿ˜ง","๐Ÿ˜ฎ","๐Ÿ˜ฒ","๐Ÿฅฑ","๐Ÿ˜ด","๐Ÿคค","๐Ÿ˜ช","๐Ÿ˜ฎโ€๐Ÿ’จ","๐Ÿ˜ต","๐Ÿ˜ตโ€๐Ÿ’ซ","๐Ÿค","๐Ÿฅด","๐Ÿคข","๐Ÿคฎ","๐Ÿคง","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿค‘","๐Ÿค ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ‘น","๐Ÿ‘บ","๐Ÿคก","๐Ÿ’ฉ","๐Ÿ‘ป","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ‘ฝ","๐Ÿ‘พ","๐Ÿค–","๐ŸŽƒ","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น","๐Ÿ˜ป","๐Ÿ˜ผ","๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ", +"๐Ÿซถ","๐Ÿซถ๐Ÿป","๐Ÿซถ๐Ÿผ","๐Ÿซถ๐Ÿฝ","๐Ÿซถ๐Ÿพ","๐Ÿซถ๐Ÿฟ", +"๐Ÿคฒ","๐Ÿคฒ๐Ÿป","๐Ÿคฒ๐Ÿผ","๐Ÿคฒ๐Ÿฝ","๐Ÿคฒ๐Ÿพ","๐Ÿคฒ๐Ÿฟ", +"๐Ÿ‘","๐Ÿ‘๐Ÿป","๐Ÿ‘๐Ÿผ","๐Ÿ‘๐Ÿฝ","๐Ÿ‘๐Ÿพ","๐Ÿ‘๐Ÿฟ", +"๐Ÿ™Œ","๐Ÿ™Œ๐Ÿป","๐Ÿ™Œ๐Ÿผ","๐Ÿ™Œ๐Ÿฝ","๐Ÿ™Œ๐Ÿพ","๐Ÿ™Œ๐Ÿฟ", +"๐Ÿ‘","๐Ÿ‘๐Ÿป","๐Ÿ‘๐Ÿผ","๐Ÿ‘๐Ÿฝ","๐Ÿ‘๐Ÿพ","๐Ÿ‘๐Ÿฟ", +"๐Ÿค","๐Ÿค๐Ÿป","๐Ÿซฑ๐Ÿปโ€๐Ÿซฒ๐Ÿผ","๐Ÿซฑ๐Ÿปโ€๐Ÿซฒ๐Ÿฝ","๐Ÿซฑ๐Ÿปโ€๐Ÿซฒ๐Ÿพ","๐Ÿซฑ๐Ÿปโ€๐Ÿซฒ๐Ÿฟ","๐Ÿซฑ๐Ÿผโ€๐Ÿซฒ๐Ÿป","๐Ÿค๐Ÿผ","๐Ÿซฑ๐Ÿผโ€๐Ÿซฒ๐Ÿฝ","๐Ÿซฑ๐Ÿผโ€๐Ÿซฒ๐Ÿพ","๐Ÿซฑ๐Ÿผโ€๐Ÿซฒ๐Ÿฟ","๐Ÿซฑ๐Ÿฝโ€๐Ÿซฒ๐Ÿป","๐Ÿซฑ๐Ÿฝโ€๐Ÿซฒ๐Ÿผ","๐Ÿค๐Ÿฝ","๐Ÿซฑ๐Ÿฝโ€๐Ÿซฒ๐Ÿพ","๐Ÿซฑ๐Ÿฝโ€๐Ÿซฒ๐Ÿฟ","๐Ÿซฑ๐Ÿพโ€๐Ÿซฒ๐Ÿป","๐Ÿซฑ๐Ÿพโ€๐Ÿซฒ๐Ÿผ","๐Ÿซฑ๐Ÿพโ€๐Ÿซฒ๐Ÿฝ","๐Ÿค๐Ÿพ","๐Ÿซฑ๐Ÿพโ€๐Ÿซฒ๐Ÿฟ","๐Ÿซฑ๐Ÿฟโ€๐Ÿซฒ๐Ÿป","๐Ÿซฑ๐Ÿฟโ€๐Ÿซฒ๐Ÿผ","๐Ÿซฑ๐Ÿฟโ€๐Ÿซฒ๐Ÿฝ","๐Ÿซฑ๐Ÿฟโ€๐Ÿซฒ๐Ÿพ","๐Ÿค๐Ÿฟ", +"๐Ÿ‘","๐Ÿ‘๐Ÿป","๐Ÿ‘๐Ÿผ","๐Ÿ‘๐Ÿฝ","๐Ÿ‘๐Ÿพ","๐Ÿ‘๐Ÿฟ", +"๐Ÿ‘Ž","๐Ÿ‘Ž๐Ÿป","๐Ÿ‘Ž๐Ÿผ","๐Ÿ‘Ž๐Ÿฝ","๐Ÿ‘Ž๐Ÿพ","๐Ÿ‘Ž๐Ÿฟ", +"๐Ÿ‘Š","๐Ÿ‘Š๐Ÿป","๐Ÿ‘Š๐Ÿผ","๐Ÿ‘Š๐Ÿฝ","๐Ÿ‘Š๐Ÿพ","๐Ÿ‘Š๐Ÿฟ", +"โœŠ","โœŠ๐Ÿป","โœŠ๐Ÿผ","โœŠ๐Ÿฝ","โœŠ๐Ÿพ","โœŠ๐Ÿฟ", +"๐Ÿค›","๐Ÿค›๐Ÿป","๐Ÿค›๐Ÿผ","๐Ÿค›๐Ÿฝ","๐Ÿค›๐Ÿพ","๐Ÿค›๐Ÿฟ", +"๐Ÿคœ","๐Ÿคœ๐Ÿป","๐Ÿคœ๐Ÿผ","๐Ÿคœ๐Ÿฝ","๐Ÿคœ๐Ÿพ","๐Ÿคœ๐Ÿฟ", +"๐Ÿคž","๐Ÿคž๐Ÿป","๐Ÿคž๐Ÿผ","๐Ÿคž๐Ÿฝ","๐Ÿคž๐Ÿพ","๐Ÿคž๐Ÿฟ", +"โœŒ๏ธ","โœŒ๐Ÿป","โœŒ๐Ÿผ","โœŒ๐Ÿฝ","โœŒ๐Ÿพ","โœŒ๐Ÿฟ", +"๐Ÿซฐ","๐Ÿซฐ๐Ÿป","๐Ÿซฐ๐Ÿผ","๐Ÿซฐ๐Ÿฝ","๐Ÿซฐ๐Ÿพ","๐Ÿซฐ๐Ÿฟ", +"๐ŸคŸ","๐ŸคŸ๐Ÿป","๐ŸคŸ๐Ÿผ","๐ŸคŸ๐Ÿฝ","๐ŸคŸ๐Ÿพ","๐ŸคŸ๐Ÿฟ", +"๐Ÿค˜","๐Ÿค˜๐Ÿป","๐Ÿค˜๐Ÿผ","๐Ÿค˜๐Ÿฝ","๐Ÿค˜๐Ÿพ","๐Ÿค˜๐Ÿฟ", +"๐Ÿ‘Œ","๐Ÿ‘Œ๐Ÿป","๐Ÿ‘Œ๐Ÿผ","๐Ÿ‘Œ๐Ÿฝ","๐Ÿ‘Œ๐Ÿพ","๐Ÿ‘Œ๐Ÿฟ", +"๐ŸคŒ","๐ŸคŒ๐Ÿป","๐ŸคŒ๐Ÿผ","๐ŸคŒ๐Ÿฝ","๐ŸคŒ๐Ÿพ","๐ŸคŒ๐Ÿฟ", +"๐Ÿค","๐Ÿค๐Ÿป","๐Ÿค๐Ÿผ","๐Ÿค๐Ÿฝ","๐Ÿค๐Ÿพ","๐Ÿค๐Ÿฟ", +"๐Ÿซณ","๐Ÿซณ๐Ÿป","๐Ÿซณ๐Ÿผ","๐Ÿซณ๐Ÿฝ","๐Ÿซณ๐Ÿพ","๐Ÿซณ๐Ÿฟ", +"๐Ÿซด","๐Ÿซด๐Ÿป","๐Ÿซด๐Ÿผ","๐Ÿซด๐Ÿฝ","๐Ÿซด๐Ÿพ","๐Ÿซด๐Ÿฟ", +"๐Ÿ‘ˆ","๐Ÿ‘ˆ๐Ÿป","๐Ÿ‘ˆ๐Ÿผ","๐Ÿ‘ˆ๐Ÿฝ","๐Ÿ‘ˆ๐Ÿพ","๐Ÿ‘ˆ๐Ÿฟ", +"๐Ÿ‘‰","๐Ÿ‘‰๐Ÿป","๐Ÿ‘‰๐Ÿผ","๐Ÿ‘‰๐Ÿฝ","๐Ÿ‘‰๐Ÿพ","๐Ÿ‘‰๐Ÿฟ", +"๐Ÿ‘†","๐Ÿ‘†๐Ÿป","๐Ÿ‘†๐Ÿผ","๐Ÿ‘†๐Ÿฝ","๐Ÿ‘†๐Ÿพ","๐Ÿ‘†๐Ÿฟ", +"๐Ÿ‘‡","๐Ÿ‘‡๐Ÿป","๐Ÿ‘‡๐Ÿผ","๐Ÿ‘‡๐Ÿฝ","๐Ÿ‘‡๐Ÿพ","๐Ÿ‘‡๐Ÿฟ", +"โ˜๏ธ","โ˜๐Ÿป","โ˜๐Ÿผ","โ˜๐Ÿฝ","โ˜๐Ÿพ","โ˜๐Ÿฟ", +"โœ‹","โœ‹๐Ÿป","โœ‹๐Ÿผ","โœ‹๐Ÿฝ","โœ‹๐Ÿพ","โœ‹๐Ÿฟ", +"๐Ÿคš","๐Ÿคš๐Ÿป","๐Ÿคš๐Ÿผ","๐Ÿคš๐Ÿฝ","๐Ÿคš๐Ÿพ","๐Ÿคš๐Ÿฟ", +"๐Ÿ–","๐Ÿ–๐Ÿป","๐Ÿ–๐Ÿผ","๐Ÿ–๐Ÿฝ","๐Ÿ–๐Ÿพ","๐Ÿ–๐Ÿฟ", +"๐Ÿ––","๐Ÿ––๐Ÿป","๐Ÿ––๐Ÿผ","๐Ÿ––๐Ÿฝ","๐Ÿ––๐Ÿพ","๐Ÿ––๐Ÿฟ", +"๐Ÿ‘‹","๐Ÿ‘‹๐Ÿป","๐Ÿ‘‹๐Ÿผ","๐Ÿ‘‹๐Ÿฝ","๐Ÿ‘‹๐Ÿพ","๐Ÿ‘‹๐Ÿฟ", +"๐Ÿค™","๐Ÿค™๐Ÿป","๐Ÿค™๐Ÿผ","๐Ÿค™๐Ÿฝ","๐Ÿค™๐Ÿพ","๐Ÿค™๐Ÿฟ", +"๐Ÿซฒ","๐Ÿซฒ๐Ÿป","๐Ÿซฒ๐Ÿผ","๐Ÿซฒ๐Ÿฝ","๐Ÿซฒ๐Ÿพ","๐Ÿซฒ๐Ÿฟ", +"๐Ÿซฑ","๐Ÿซฑ๐Ÿป","๐Ÿซฑ๐Ÿผ","๐Ÿซฑ๐Ÿฝ","๐Ÿซฑ๐Ÿพ","๐Ÿซฑ๐Ÿฟ", +"๐Ÿ’ช","๐Ÿ’ช๐Ÿป","๐Ÿ’ช๐Ÿผ","๐Ÿ’ช๐Ÿฝ","๐Ÿ’ช๐Ÿพ","๐Ÿ’ช๐Ÿฟ", +"๐Ÿฆพ", +"๐Ÿ–•","๐Ÿ–•๐Ÿป","๐Ÿ–•๐Ÿผ","๐Ÿ–•๐Ÿฝ","๐Ÿ–•๐Ÿพ","๐Ÿ–•๐Ÿฟ", +"โœ๏ธ","โœ๐Ÿป","โœ๐Ÿผ","โœ๐Ÿฝ","โœ๐Ÿพ","โœ๐Ÿฟ", +"๐Ÿ™","๐Ÿ™๐Ÿป","๐Ÿ™๐Ÿผ","๐Ÿ™๐Ÿฝ","๐Ÿ™๐Ÿพ","๐Ÿ™๐Ÿฟ", +"๐Ÿซต","๐Ÿซต๐Ÿป","๐Ÿซต๐Ÿผ","๐Ÿซต๐Ÿฝ","๐Ÿซต๐Ÿพ","๐Ÿซต๐Ÿฟ", +"๐Ÿฆถ","๐Ÿฆถ๐Ÿป","๐Ÿฆถ๐Ÿผ","๐Ÿฆถ๐Ÿฝ","๐Ÿฆถ๐Ÿพ","๐Ÿฆถ๐Ÿฟ", +"๐Ÿฆต","๐Ÿฆต๐Ÿป","๐Ÿฆต๐Ÿผ","๐Ÿฆต๐Ÿฝ","๐Ÿฆต๐Ÿพ","๐Ÿฆต๐Ÿฟ", +"๐Ÿฆฟ","๐Ÿ’„","๐Ÿ’‹","๐Ÿ‘„","๐Ÿซฆ","๐Ÿฆท","๐Ÿ‘…", +"๐Ÿ‘‚","๐Ÿ‘‚๐Ÿป","๐Ÿ‘‚๐Ÿผ","๐Ÿ‘‚๐Ÿฝ","๐Ÿ‘‚๐Ÿพ","๐Ÿ‘‚๐Ÿฟ", +"๐Ÿฆป","๐Ÿฆป๐Ÿป","๐Ÿฆป๐Ÿผ","๐Ÿฆป๐Ÿฝ","๐Ÿฆป๐Ÿพ","๐Ÿฆป๐Ÿฟ", +"๐Ÿ‘ƒ","๐Ÿ‘ƒ๐Ÿป","๐Ÿ‘ƒ๐Ÿผ","๐Ÿ‘ƒ๐Ÿฝ","๐Ÿ‘ƒ๐Ÿพ","๐Ÿ‘ƒ๐Ÿฟ", +"๐Ÿ‘ฃ","๐Ÿ‘","๐Ÿ‘€","๐Ÿซ€","๐Ÿซ","๐Ÿง ","๐Ÿ—ฃ","๐Ÿ‘ค","๐Ÿ‘ฅ","๐Ÿซ‚", +"๐Ÿ‘ถ","๐Ÿ‘ถ๐Ÿป","๐Ÿ‘ถ๐Ÿผ","๐Ÿ‘ถ๐Ÿฝ","๐Ÿ‘ถ๐Ÿพ","๐Ÿ‘ถ๐Ÿฟ", +"๐Ÿ‘ง","๐Ÿ‘ง๐Ÿป","๐Ÿ‘ง๐Ÿผ","๐Ÿ‘ง๐Ÿฝ","๐Ÿ‘ง๐Ÿพ","๐Ÿ‘ง๐Ÿฟ", +"๐Ÿง’","๐Ÿง’๐Ÿป","๐Ÿง’๐Ÿผ","๐Ÿง’๐Ÿฝ","๐Ÿง’๐Ÿพ","๐Ÿง’๐Ÿฟ", +"๐Ÿ‘ฆ","๐Ÿ‘ฆ๐Ÿป","๐Ÿ‘ฆ๐Ÿผ","๐Ÿ‘ฆ๐Ÿฝ","๐Ÿ‘ฆ๐Ÿพ","๐Ÿ‘ฆ๐Ÿฟ", +"๐Ÿ‘ฉ","๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟ", +"๐Ÿง‘","๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฟ", +"๐Ÿ‘จ","๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘ฉโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฑ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฑ", +"๐Ÿง‘โ€๐Ÿฆฑ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฑ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฑ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฑ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฑ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฑ", +"๐Ÿ‘จโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฑ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฑ", +"๐Ÿ‘ฉโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฐ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฐ", +"๐Ÿง‘โ€๐Ÿฆฐ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฐ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฐ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฐ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฐ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฐ", +"๐Ÿ‘จโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฐ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฐ", +"๐Ÿ‘ฑโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ฑ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ฑ","๐Ÿ‘ฑ๐Ÿป","๐Ÿ‘ฑ๐Ÿผ","๐Ÿ‘ฑ๐Ÿฝ","๐Ÿ‘ฑ๐Ÿพ","๐Ÿ‘ฑ๐Ÿฟ", +"๐Ÿ‘ฑโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ฑ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆณ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆณ", +"๐Ÿง‘โ€๐Ÿฆณ","๐Ÿง‘๐Ÿปโ€๐Ÿฆณ","๐Ÿง‘๐Ÿผโ€๐Ÿฆณ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆณ","๐Ÿง‘๐Ÿพโ€๐Ÿฆณ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆณ", +"๐Ÿ‘จโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆณ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆณ", +"๐Ÿ‘ฉโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฒ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฒ", +"๐Ÿง‘โ€๐Ÿฆฒ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฒ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฒ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฒ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฒ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฒ", +"๐Ÿ‘จโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฒ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฒ", +"๐Ÿง”โ€โ™€๏ธ","๐Ÿง”๐Ÿปโ€โ™€๏ธ","๐Ÿง”๐Ÿผโ€โ™€๏ธ","๐Ÿง”๐Ÿฝโ€โ™€๏ธ","๐Ÿง”๐Ÿพโ€โ™€๏ธ","๐Ÿง”๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง”","๐Ÿง”๐Ÿป","๐Ÿง”๐Ÿผ","๐Ÿง”๐Ÿฝ","๐Ÿง”๐Ÿพ","๐Ÿง”๐Ÿฟ", +"๐Ÿง”โ€โ™‚๏ธ","๐Ÿง”๐Ÿปโ€โ™‚๏ธ","๐Ÿง”๐Ÿผโ€โ™‚๏ธ","๐Ÿง”๐Ÿฝโ€โ™‚๏ธ","๐Ÿง”๐Ÿพโ€โ™‚๏ธ","๐Ÿง”๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ต","๐Ÿ‘ต๐Ÿป","๐Ÿ‘ต๐Ÿผ","๐Ÿ‘ต๐Ÿฝ","๐Ÿ‘ต๐Ÿพ","๐Ÿ‘ต๐Ÿฟ", +"๐Ÿง“","๐Ÿง“๐Ÿป","๐Ÿง“๐Ÿผ","๐Ÿง“๐Ÿฝ","๐Ÿง“๐Ÿพ","๐Ÿง“๐Ÿฟ", +"๐Ÿ‘ด","๐Ÿ‘ด๐Ÿป","๐Ÿ‘ด๐Ÿผ","๐Ÿ‘ด๐Ÿฝ","๐Ÿ‘ด๐Ÿพ","๐Ÿ‘ด๐Ÿฟ", +"๐Ÿ‘ฒ","๐Ÿ‘ฒ๐Ÿป","๐Ÿ‘ฒ๐Ÿผ","๐Ÿ‘ฒ๐Ÿฝ","๐Ÿ‘ฒ๐Ÿพ","๐Ÿ‘ฒ๐Ÿฟ", +"๐Ÿ‘ณโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ณ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ณ","๐Ÿ‘ณ๐Ÿป","๐Ÿ‘ณ๐Ÿผ","๐Ÿ‘ณ๐Ÿฝ","๐Ÿ‘ณ๐Ÿพ","๐Ÿ‘ณ๐Ÿฟ", +"๐Ÿ‘ณโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ณ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿง•","๐Ÿง•๐Ÿป","๐Ÿง•๐Ÿผ","๐Ÿง•๐Ÿฝ","๐Ÿง•๐Ÿพ","๐Ÿง•๐Ÿฟ", +"๐Ÿ‘ฎโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ฎ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ฎ","๐Ÿ‘ฎ๐Ÿป","๐Ÿ‘ฎ๐Ÿผ","๐Ÿ‘ฎ๐Ÿฝ","๐Ÿ‘ฎ๐Ÿพ","๐Ÿ‘ฎ๐Ÿฟ", +"๐Ÿ‘ฎโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ฎ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ทโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ท๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ท","๐Ÿ‘ท๐Ÿป","๐Ÿ‘ท๐Ÿผ","๐Ÿ‘ท๐Ÿฝ","๐Ÿ‘ท๐Ÿพ","๐Ÿ‘ท๐Ÿฟ", +"๐Ÿ‘ทโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ท๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’‚โ€โ™€๏ธ","๐Ÿ’‚๐Ÿปโ€โ™€๏ธ","๐Ÿ’‚๐Ÿผโ€โ™€๏ธ","๐Ÿ’‚๐Ÿฝโ€โ™€๏ธ","๐Ÿ’‚๐Ÿพโ€โ™€๏ธ","๐Ÿ’‚๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ’‚","๐Ÿ’‚๐Ÿป","๐Ÿ’‚๐Ÿผ","๐Ÿ’‚๐Ÿฝ","๐Ÿ’‚๐Ÿพ","๐Ÿ’‚๐Ÿฟ", +"๐Ÿ’‚โ€โ™‚๏ธ","๐Ÿ’‚๐Ÿปโ€โ™‚๏ธ","๐Ÿ’‚๐Ÿผโ€โ™‚๏ธ","๐Ÿ’‚๐Ÿฝโ€โ™‚๏ธ","๐Ÿ’‚๐Ÿพโ€โ™‚๏ธ","๐Ÿ’‚๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ•ต๏ธโ€โ™€๏ธ","๐Ÿ•ต๐Ÿปโ€โ™€๏ธ","๐Ÿ•ต๐Ÿผโ€โ™€๏ธ","๐Ÿ•ต๐Ÿฝโ€โ™€๏ธ","๐Ÿ•ต๐Ÿพโ€โ™€๏ธ","๐Ÿ•ต๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ•ต๏ธ","๐Ÿ•ต๐Ÿป","๐Ÿ•ต๐Ÿผ","๐Ÿ•ต๐Ÿฝ","๐Ÿ•ต๐Ÿพ","๐Ÿ•ต๐Ÿฟ", +"๐Ÿ•ต๏ธโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿปโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿผโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿฝโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿพโ€โ™‚๏ธ","๐Ÿ•ต๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿปโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿผโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿฝโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿพโ€โš•๏ธ","๐Ÿ‘ฉ๐Ÿฟโ€โš•๏ธ", +"๐Ÿง‘โ€โš•๏ธ","๐Ÿง‘๐Ÿปโ€โš•๏ธ","๐Ÿง‘๐Ÿผโ€โš•๏ธ","๐Ÿง‘๐Ÿฝโ€โš•๏ธ","๐Ÿง‘๐Ÿพโ€โš•๏ธ","๐Ÿง‘๐Ÿฟโ€โš•๏ธ", +"๐Ÿ‘จโ€โš•๏ธ","๐Ÿ‘จ๐Ÿปโ€โš•๏ธ","๐Ÿ‘จ๐Ÿผโ€โš•๏ธ","๐Ÿ‘จ๐Ÿฝโ€โš•๏ธ","๐Ÿ‘จ๐Ÿพโ€โš•๏ธ","๐Ÿ‘จ๐Ÿฟโ€โš•๏ธ", +"๐Ÿ‘ฉโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿปโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿผโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿพโ€๐ŸŒพ","๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŒพ", +"๐Ÿง‘โ€๐ŸŒพ","๐Ÿง‘๐Ÿปโ€๐ŸŒพ","๐Ÿง‘๐Ÿผโ€๐ŸŒพ","๐Ÿง‘๐Ÿฝโ€๐ŸŒพ","๐Ÿง‘๐Ÿพโ€๐ŸŒพ","๐Ÿง‘๐Ÿฟโ€๐ŸŒพ", +"๐Ÿ‘จโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿปโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿผโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿฝโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿพโ€๐ŸŒพ","๐Ÿ‘จ๐Ÿฟโ€๐ŸŒพ", +"๐Ÿ‘ฉโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿณ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿณ", +"๐Ÿง‘โ€๐Ÿณ","๐Ÿง‘๐Ÿปโ€๐Ÿณ","๐Ÿง‘๐Ÿผโ€๐Ÿณ","๐Ÿง‘๐Ÿฝโ€๐Ÿณ","๐Ÿง‘๐Ÿพโ€๐Ÿณ","๐Ÿง‘๐Ÿฟโ€๐Ÿณ", +"๐Ÿ‘จโ€๐Ÿณ","๐Ÿ‘จ๐Ÿปโ€๐Ÿณ","๐Ÿ‘จ๐Ÿผโ€๐Ÿณ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿณ","๐Ÿ‘จ๐Ÿพโ€๐Ÿณ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿณ", +"๐Ÿ‘ฉโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿผโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿพโ€๐ŸŽ“","๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŽ“", +"๐Ÿง‘โ€๐ŸŽ“","๐Ÿง‘๐Ÿปโ€๐ŸŽ“","๐Ÿง‘๐Ÿผโ€๐ŸŽ“","๐Ÿง‘๐Ÿฝโ€๐ŸŽ“","๐Ÿง‘๐Ÿพโ€๐ŸŽ“","๐Ÿง‘๐Ÿฟโ€๐ŸŽ“", +"๐Ÿ‘จโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿปโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿผโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿฝโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿพโ€๐ŸŽ“","๐Ÿ‘จ๐Ÿฟโ€๐ŸŽ“", +"๐Ÿ‘ฉโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿผโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿพโ€๐ŸŽค","๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŽค", +"๐Ÿง‘โ€๐ŸŽค","๐Ÿง‘๐Ÿปโ€๐ŸŽค","๐Ÿง‘๐Ÿผโ€๐ŸŽค","๐Ÿง‘๐Ÿฝโ€๐ŸŽค","๐Ÿง‘๐Ÿพโ€๐ŸŽค","๐Ÿง‘๐Ÿฟโ€๐ŸŽค", +"๐Ÿ‘จโ€๐ŸŽค","๐Ÿ‘จ๐Ÿปโ€๐ŸŽค","๐Ÿ‘จ๐Ÿผโ€๐ŸŽค","๐Ÿ‘จ๐Ÿฝโ€๐ŸŽค","๐Ÿ‘จ๐Ÿพโ€๐ŸŽค","๐Ÿ‘จ๐Ÿฟโ€๐ŸŽค", +"๐Ÿ‘ฉโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿซ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿซ", +"๐Ÿง‘โ€๐Ÿซ","๐Ÿง‘๐Ÿปโ€๐Ÿซ","๐Ÿง‘๐Ÿผโ€๐Ÿซ","๐Ÿง‘๐Ÿฝโ€๐Ÿซ","๐Ÿง‘๐Ÿพโ€๐Ÿซ","๐Ÿง‘๐Ÿฟโ€๐Ÿซ", +"๐Ÿ‘จโ€๐Ÿซ","๐Ÿ‘จ๐Ÿปโ€๐Ÿซ","๐Ÿ‘จ๐Ÿผโ€๐Ÿซ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿซ","๐Ÿ‘จ๐Ÿพโ€๐Ÿซ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿซ", +"๐Ÿ‘ฉโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿญ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿญ", +"๐Ÿง‘โ€๐Ÿญ","๐Ÿง‘๐Ÿปโ€๐Ÿญ","๐Ÿง‘๐Ÿผโ€๐Ÿญ","๐Ÿง‘๐Ÿฝโ€๐Ÿญ","๐Ÿง‘๐Ÿพโ€๐Ÿญ","๐Ÿง‘๐Ÿฟโ€๐Ÿญ", +"๐Ÿ‘จโ€๐Ÿญ","๐Ÿ‘จ๐Ÿปโ€๐Ÿญ","๐Ÿ‘จ๐Ÿผโ€๐Ÿญ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿญ","๐Ÿ‘จ๐Ÿพโ€๐Ÿญ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿญ", +"๐Ÿ‘ฉโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ’ป","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ’ป", +"๐Ÿง‘โ€๐Ÿ’ป","๐Ÿง‘๐Ÿปโ€๐Ÿ’ป","๐Ÿง‘๐Ÿผโ€๐Ÿ’ป","๐Ÿง‘๐Ÿฝโ€๐Ÿ’ป","๐Ÿง‘๐Ÿพโ€๐Ÿ’ป","๐Ÿง‘๐Ÿฟโ€๐Ÿ’ป", +"๐Ÿ‘จโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿผโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿฝโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿพโ€๐Ÿ’ป","๐Ÿ‘จ๐Ÿฟโ€๐Ÿ’ป", +"๐Ÿ‘ฉโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ’ผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ’ผ", +"๐Ÿง‘โ€๐Ÿ’ผ","๐Ÿง‘๐Ÿปโ€๐Ÿ’ผ","๐Ÿง‘๐Ÿผโ€๐Ÿ’ผ","๐Ÿง‘๐Ÿฝโ€๐Ÿ’ผ","๐Ÿง‘๐Ÿพโ€๐Ÿ’ผ","๐Ÿง‘๐Ÿฟโ€๐Ÿ’ผ", +"๐Ÿ‘จโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿผโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿพโ€๐Ÿ’ผ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿ’ผ", +"๐Ÿ‘ฉโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ”ง","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ”ง", +"๐Ÿง‘โ€๐Ÿ”ง","๐Ÿง‘๐Ÿปโ€๐Ÿ”ง","๐Ÿง‘๐Ÿผโ€๐Ÿ”ง","๐Ÿง‘๐Ÿฝโ€๐Ÿ”ง","๐Ÿง‘๐Ÿพโ€๐Ÿ”ง","๐Ÿง‘๐Ÿฟโ€๐Ÿ”ง", +"๐Ÿ‘จโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿปโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿผโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿฝโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿพโ€๐Ÿ”ง","๐Ÿ‘จ๐Ÿฟโ€๐Ÿ”ง", +"๐Ÿ‘ฉโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ”ฌ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ”ฌ", +"๐Ÿง‘โ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿปโ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿผโ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿฝโ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿพโ€๐Ÿ”ฌ","๐Ÿง‘๐Ÿฟโ€๐Ÿ”ฌ", +"๐Ÿ‘จโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿปโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿผโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿพโ€๐Ÿ”ฌ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿ”ฌ", +"๐Ÿ‘ฉโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿผโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿพโ€๐ŸŽจ","๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŽจ", +"๐Ÿง‘โ€๐ŸŽจ","๐Ÿง‘๐Ÿปโ€๐ŸŽจ","๐Ÿง‘๐Ÿผโ€๐ŸŽจ","๐Ÿง‘๐Ÿฝโ€๐ŸŽจ","๐Ÿง‘๐Ÿพโ€๐ŸŽจ","๐Ÿง‘๐Ÿฟโ€๐ŸŽจ", +"๐Ÿ‘จโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿปโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿผโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿฝโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿพโ€๐ŸŽจ","๐Ÿ‘จ๐Ÿฟโ€๐ŸŽจ", +"๐Ÿ‘ฉโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿš’","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿš’", +"๐Ÿง‘โ€๐Ÿš’","๐Ÿง‘๐Ÿปโ€๐Ÿš’","๐Ÿง‘๐Ÿผโ€๐Ÿš’","๐Ÿง‘๐Ÿฝโ€๐Ÿš’","๐Ÿง‘๐Ÿพโ€๐Ÿš’","๐Ÿง‘๐Ÿฟโ€๐Ÿš’", +"๐Ÿ‘จโ€๐Ÿš’","๐Ÿ‘จ๐Ÿปโ€๐Ÿš’","๐Ÿ‘จ๐Ÿผโ€๐Ÿš’","๐Ÿ‘จ๐Ÿฝโ€๐Ÿš’","๐Ÿ‘จ๐Ÿพโ€๐Ÿš’","๐Ÿ‘จ๐Ÿฟโ€๐Ÿš’", +"๐Ÿ‘ฉโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿปโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿผโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿฝโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿพโ€โœˆ๏ธ","๐Ÿ‘ฉ๐Ÿฟโ€โœˆ๏ธ", +"๐Ÿง‘โ€โœˆ๏ธ","๐Ÿง‘๐Ÿปโ€โœˆ๏ธ","๐Ÿง‘๐Ÿผโ€โœˆ๏ธ","๐Ÿง‘๐Ÿฝโ€โœˆ๏ธ","๐Ÿง‘๐Ÿพโ€โœˆ๏ธ","๐Ÿง‘๐Ÿฟโ€โœˆ๏ธ", +"๐Ÿ‘จโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿปโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿผโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿฝโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿพโ€โœˆ๏ธ","๐Ÿ‘จ๐Ÿฟโ€โœˆ๏ธ", +"๐Ÿ‘ฉโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿš€","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿš€", +"๐Ÿง‘โ€๐Ÿš€","๐Ÿง‘๐Ÿปโ€๐Ÿš€","๐Ÿง‘๐Ÿผโ€๐Ÿš€","๐Ÿง‘๐Ÿฝโ€๐Ÿš€","๐Ÿง‘๐Ÿพโ€๐Ÿš€","๐Ÿง‘๐Ÿฟโ€๐Ÿš€", +"๐Ÿ‘จโ€๐Ÿš€","๐Ÿ‘จ๐Ÿปโ€๐Ÿš€","๐Ÿ‘จ๐Ÿผโ€๐Ÿš€","๐Ÿ‘จ๐Ÿฝโ€๐Ÿš€","๐Ÿ‘จ๐Ÿพโ€๐Ÿš€","๐Ÿ‘จ๐Ÿฟโ€๐Ÿš€", +"๐Ÿ‘ฉโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿปโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿผโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿฝโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿพโ€โš–๏ธ","๐Ÿ‘ฉ๐Ÿฟโ€โš–๏ธ", +"๐Ÿง‘โ€โš–๏ธ","๐Ÿง‘๐Ÿปโ€โš–๏ธ","๐Ÿง‘๐Ÿผโ€โš–๏ธ","๐Ÿง‘๐Ÿฝโ€โš–๏ธ","๐Ÿง‘๐Ÿพโ€โš–๏ธ","๐Ÿง‘๐Ÿฟโ€โš–๏ธ", +"๐Ÿ‘จโ€โš–๏ธ","๐Ÿ‘จ๐Ÿปโ€โš–๏ธ","๐Ÿ‘จ๐Ÿผโ€โš–๏ธ","๐Ÿ‘จ๐Ÿฝโ€โš–๏ธ","๐Ÿ‘จ๐Ÿพโ€โš–๏ธ","๐Ÿ‘จ๐Ÿฟโ€โš–๏ธ", +"๐Ÿ‘ฐโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿปโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿผโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿฝโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿพโ€โ™€๏ธ","๐Ÿ‘ฐ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‘ฐ","๐Ÿ‘ฐ๐Ÿป","๐Ÿ‘ฐ๐Ÿผ","๐Ÿ‘ฐ๐Ÿฝ","๐Ÿ‘ฐ๐Ÿพ","๐Ÿ‘ฐ๐Ÿฟ", +"๐Ÿ‘ฐโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿปโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿผโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿพโ€โ™‚๏ธ","๐Ÿ‘ฐ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคตโ€โ™€๏ธ","๐Ÿคต๐Ÿปโ€โ™€๏ธ","๐Ÿคต๐Ÿผโ€โ™€๏ธ","๐Ÿคต๐Ÿฝโ€โ™€๏ธ","๐Ÿคต๐Ÿพโ€โ™€๏ธ","๐Ÿคต๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคต","๐Ÿคต๐Ÿป","๐Ÿคต๐Ÿผ","๐Ÿคต๐Ÿฝ","๐Ÿคต๐Ÿพ","๐Ÿคต๐Ÿฟ", +"๐Ÿคตโ€โ™‚๏ธ","๐Ÿคต๐Ÿปโ€โ™‚๏ธ","๐Ÿคต๐Ÿผโ€โ™‚๏ธ","๐Ÿคต๐Ÿฝโ€โ™‚๏ธ","๐Ÿคต๐Ÿพโ€โ™‚๏ธ","๐Ÿคต๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ธ","๐Ÿ‘ธ๐Ÿป","๐Ÿ‘ธ๐Ÿผ","๐Ÿ‘ธ๐Ÿฝ","๐Ÿ‘ธ๐Ÿพ","๐Ÿ‘ธ๐Ÿฟ", +"๐Ÿซ…","๐Ÿซ…๐Ÿป","๐Ÿซ…๐Ÿผ","๐Ÿซ…๐Ÿฝ","๐Ÿซ…๐Ÿพ","๐Ÿซ…๐Ÿฟ", +"๐Ÿคด","๐Ÿคด๐Ÿป","๐Ÿคด๐Ÿผ","๐Ÿคด๐Ÿฝ","๐Ÿคด๐Ÿพ","๐Ÿคด๐Ÿฟ", +"๐Ÿฅท","๐Ÿฅท๐Ÿป","๐Ÿฅท๐Ÿผ","๐Ÿฅท๐Ÿฝ","๐Ÿฅท๐Ÿพ","๐Ÿฅท๐Ÿฟ", +"๐Ÿฆธโ€โ™€๏ธ","๐Ÿฆธ๐Ÿปโ€โ™€๏ธ","๐Ÿฆธ๐Ÿผโ€โ™€๏ธ","๐Ÿฆธ๐Ÿฝโ€โ™€๏ธ","๐Ÿฆธ๐Ÿพโ€โ™€๏ธ","๐Ÿฆธ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿฆธ","๐Ÿฆธ๐Ÿป","๐Ÿฆธ๐Ÿผ","๐Ÿฆธ๐Ÿฝ","๐Ÿฆธ๐Ÿพ","๐Ÿฆธ๐Ÿฟ", +"๐Ÿฆธโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿปโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿผโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿฝโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿพโ€โ™‚๏ธ","๐Ÿฆธ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿฆนโ€โ™€๏ธ","๐Ÿฆน๐Ÿปโ€โ™€๏ธ","๐Ÿฆน๐Ÿผโ€โ™€๏ธ","๐Ÿฆน๐Ÿฝโ€โ™€๏ธ","๐Ÿฆน๐Ÿพโ€โ™€๏ธ","๐Ÿฆน๐Ÿฟโ€โ™€๏ธ", +"๐Ÿฆน","๐Ÿฆน๐Ÿป","๐Ÿฆน๐Ÿผ","๐Ÿฆน๐Ÿฝ","๐Ÿฆน๐Ÿพ","๐Ÿฆน๐Ÿฟ", +"๐Ÿฆนโ€โ™‚๏ธ","๐Ÿฆน๐Ÿปโ€โ™‚๏ธ","๐Ÿฆน๐Ÿผโ€โ™‚๏ธ","๐Ÿฆน๐Ÿฝโ€โ™‚๏ธ","๐Ÿฆน๐Ÿพโ€โ™‚๏ธ","๐Ÿฆน๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคถ","๐Ÿคถ๐Ÿป","๐Ÿคถ๐Ÿผ","๐Ÿคถ๐Ÿฝ","๐Ÿคถ๐Ÿพ","๐Ÿคถ๐Ÿฟ", +"๐Ÿง‘โ€๐ŸŽ„","๐Ÿง‘๐Ÿปโ€๐ŸŽ„","๐Ÿง‘๐Ÿผโ€๐ŸŽ„","๐Ÿง‘๐Ÿฝโ€๐ŸŽ„","๐Ÿง‘๐Ÿพโ€๐ŸŽ„","๐Ÿง‘๐Ÿฟโ€๐ŸŽ„", +"๐ŸŽ…","๐ŸŽ…๐Ÿป","๐ŸŽ…๐Ÿผ","๐ŸŽ…๐Ÿฝ","๐ŸŽ…๐Ÿพ","๐ŸŽ…๐Ÿฟ", +"๐Ÿง™โ€โ™€๏ธ","๐Ÿง™๐Ÿปโ€โ™€๏ธ","๐Ÿง™๐Ÿผโ€โ™€๏ธ","๐Ÿง™๐Ÿฝโ€โ™€๏ธ","๐Ÿง™๐Ÿพโ€โ™€๏ธ","๐Ÿง™๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง™","๐Ÿง™๐Ÿป","๐Ÿง™๐Ÿผ","๐Ÿง™๐Ÿฝ","๐Ÿง™๐Ÿพ","๐Ÿง™๐Ÿฟ", +"๐Ÿง™โ€โ™‚๏ธ","๐Ÿง™๐Ÿปโ€โ™‚๏ธ","๐Ÿง™๐Ÿผโ€โ™‚๏ธ","๐Ÿง™๐Ÿฝโ€โ™‚๏ธ","๐Ÿง™๐Ÿพโ€โ™‚๏ธ","๐Ÿง™๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ","๐Ÿง๐Ÿปโ€โ™€๏ธ","๐Ÿง๐Ÿผโ€โ™€๏ธ","๐Ÿง๐Ÿฝโ€โ™€๏ธ","๐Ÿง๐Ÿพโ€โ™€๏ธ","๐Ÿง๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง","๐Ÿง๐Ÿป","๐Ÿง๐Ÿผ","๐Ÿง๐Ÿฝ","๐Ÿง๐Ÿพ","๐Ÿง๐Ÿฟ", +"๐Ÿงโ€โ™‚๏ธ","๐Ÿง๐Ÿปโ€โ™‚๏ธ","๐Ÿง๐Ÿผโ€โ™‚๏ธ","๐Ÿง๐Ÿฝโ€โ™‚๏ธ","๐Ÿง๐Ÿพโ€โ™‚๏ธ","๐Ÿง๐Ÿฟโ€โ™‚๏ธ", +"๐ŸงŒ", +"๐Ÿง›โ€โ™€๏ธ","๐Ÿง›๐Ÿปโ€โ™€๏ธ","๐Ÿง›๐Ÿผโ€โ™€๏ธ","๐Ÿง›๐Ÿฝโ€โ™€๏ธ","๐Ÿง›๐Ÿพโ€โ™€๏ธ","๐Ÿง›๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง›","๐Ÿง›๐Ÿป","๐Ÿง›๐Ÿผ","๐Ÿง›๐Ÿฝ","๐Ÿง›๐Ÿพ","๐Ÿง›๐Ÿฟ", +"๐Ÿง›โ€โ™‚๏ธ","๐Ÿง›๐Ÿปโ€โ™‚๏ธ","๐Ÿง›๐Ÿผโ€โ™‚๏ธ","๐Ÿง›๐Ÿฝโ€โ™‚๏ธ","๐Ÿง›๐Ÿพโ€โ™‚๏ธ","๐Ÿง›๐Ÿฟโ€โ™‚๏ธ", +"๐ŸงŸโ€โ™€๏ธ","๐ŸงŸ","๐ŸงŸโ€โ™‚๏ธ","๐Ÿงžโ€โ™€๏ธ","๐Ÿงž","๐Ÿงžโ€โ™‚๏ธ", +"๐Ÿงœโ€โ™€๏ธ","๐Ÿงœ๐Ÿปโ€โ™€๏ธ","๐Ÿงœ๐Ÿผโ€โ™€๏ธ","๐Ÿงœ๐Ÿฝโ€โ™€๏ธ","๐Ÿงœ๐Ÿพโ€โ™€๏ธ","๐Ÿงœ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿงœ","๐Ÿงœ๐Ÿป","๐Ÿงœ๐Ÿผ","๐Ÿงœ๐Ÿฝ","๐Ÿงœ๐Ÿพ","๐Ÿงœ๐Ÿฟ", +"๐Ÿงœโ€โ™‚๏ธ","๐Ÿงœ๐Ÿปโ€โ™‚๏ธ","๐Ÿงœ๐Ÿผโ€โ™‚๏ธ","๐Ÿงœ๐Ÿฝโ€โ™‚๏ธ","๐Ÿงœ๐Ÿพโ€โ™‚๏ธ","๐Ÿงœ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿงšโ€โ™€๏ธ","๐Ÿงš๐Ÿปโ€โ™€๏ธ","๐Ÿงš๐Ÿผโ€โ™€๏ธ","๐Ÿงš๐Ÿฝโ€โ™€๏ธ","๐Ÿงš๐Ÿพโ€โ™€๏ธ","๐Ÿงš๐Ÿฟโ€โ™€๏ธ", +"๐Ÿงš","๐Ÿงš๐Ÿป","๐Ÿงš๐Ÿผ","๐Ÿงš๐Ÿฝ","๐Ÿงš๐Ÿพ","๐Ÿงš๐Ÿฟ", +"๐Ÿงšโ€โ™‚๏ธ","๐Ÿงš๐Ÿปโ€โ™‚๏ธ","๐Ÿงš๐Ÿผโ€โ™‚๏ธ","๐Ÿงš๐Ÿฝโ€โ™‚๏ธ","๐Ÿงš๐Ÿพโ€โ™‚๏ธ","๐Ÿงš๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ผ","๐Ÿ‘ผ๐Ÿป","๐Ÿ‘ผ๐Ÿผ","๐Ÿ‘ผ๐Ÿฝ","๐Ÿ‘ผ๐Ÿพ","๐Ÿ‘ผ๐Ÿฟ", +"๐Ÿคฐ","๐Ÿคฐ๐Ÿป","๐Ÿคฐ๐Ÿผ","๐Ÿคฐ๐Ÿฝ","๐Ÿคฐ๐Ÿพ","๐Ÿคฐ๐Ÿฟ", +"๐Ÿซ„","๐Ÿซ„๐Ÿป","๐Ÿซ„๐Ÿผ","๐Ÿซ„๐Ÿฝ","๐Ÿซ„๐Ÿพ","๐Ÿซ„๐Ÿฟ", +"๐Ÿซƒ","๐Ÿซƒ๐Ÿป","๐Ÿซƒ๐Ÿผ","๐Ÿซƒ๐Ÿฝ","๐Ÿซƒ๐Ÿพ","๐Ÿซƒ๐Ÿฟ", +"๐Ÿคฑ","๐Ÿคฑ๐Ÿป","๐Ÿคฑ๐Ÿผ","๐Ÿคฑ๐Ÿฝ","๐Ÿคฑ๐Ÿพ","๐Ÿคฑ๐Ÿฟ", +"๐Ÿ‘ฉโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿผ", +"๐Ÿง‘โ€๐Ÿผ","๐Ÿง‘๐Ÿปโ€๐Ÿผ","๐Ÿง‘๐Ÿผโ€๐Ÿผ","๐Ÿง‘๐Ÿฝโ€๐Ÿผ","๐Ÿง‘๐Ÿพโ€๐Ÿผ","๐Ÿง‘๐Ÿฟโ€๐Ÿผ", +"๐Ÿ‘จโ€๐Ÿผ","๐Ÿ‘จ๐Ÿปโ€๐Ÿผ","๐Ÿ‘จ๐Ÿผโ€๐Ÿผ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿผ","๐Ÿ‘จ๐Ÿพโ€๐Ÿผ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿผ", +"๐Ÿ™‡โ€โ™€๏ธ","๐Ÿ™‡๐Ÿปโ€โ™€๏ธ","๐Ÿ™‡๐Ÿผโ€โ™€๏ธ","๐Ÿ™‡๐Ÿฝโ€โ™€๏ธ","๐Ÿ™‡๐Ÿพโ€โ™€๏ธ","๐Ÿ™‡๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™‡","๐Ÿ™‡๐Ÿป","๐Ÿ™‡๐Ÿผ","๐Ÿ™‡๐Ÿฝ","๐Ÿ™‡๐Ÿพ","๐Ÿ™‡๐Ÿฟ", +"๐Ÿ™‡โ€โ™‚๏ธ","๐Ÿ™‡๐Ÿปโ€โ™‚๏ธ","๐Ÿ™‡๐Ÿผโ€โ™‚๏ธ","๐Ÿ™‡๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™‡๐Ÿพโ€โ™‚๏ธ","๐Ÿ™‡๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’โ€โ™€๏ธ","๐Ÿ’๐Ÿปโ€โ™€๏ธ","๐Ÿ’๐Ÿผโ€โ™€๏ธ","๐Ÿ’๐Ÿฝโ€โ™€๏ธ","๐Ÿ’๐Ÿพโ€โ™€๏ธ","๐Ÿ’๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ’","๐Ÿ’๐Ÿป","๐Ÿ’๐Ÿผ","๐Ÿ’๐Ÿฝ","๐Ÿ’๐Ÿพ","๐Ÿ’๐Ÿฟ", +"๐Ÿ’โ€โ™‚๏ธ","๐Ÿ’๐Ÿปโ€โ™‚๏ธ","๐Ÿ’๐Ÿผโ€โ™‚๏ธ","๐Ÿ’๐Ÿฝโ€โ™‚๏ธ","๐Ÿ’๐Ÿพโ€โ™‚๏ธ","๐Ÿ’๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™…โ€โ™€๏ธ","๐Ÿ™…๐Ÿปโ€โ™€๏ธ","๐Ÿ™…๐Ÿผโ€โ™€๏ธ","๐Ÿ™…๐Ÿฝโ€โ™€๏ธ","๐Ÿ™…๐Ÿพโ€โ™€๏ธ","๐Ÿ™…๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™…","๐Ÿ™…๐Ÿป","๐Ÿ™…๐Ÿผ","๐Ÿ™…๐Ÿฝ","๐Ÿ™…๐Ÿพ","๐Ÿ™…๐Ÿฟ", +"๐Ÿ™…โ€โ™‚๏ธ","๐Ÿ™…๐Ÿปโ€โ™‚๏ธ","๐Ÿ™…๐Ÿผโ€โ™‚๏ธ","๐Ÿ™…๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™…๐Ÿพโ€โ™‚๏ธ","๐Ÿ™…๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™†โ€โ™€๏ธ","๐Ÿ™†๐Ÿปโ€โ™€๏ธ","๐Ÿ™†๐Ÿผโ€โ™€๏ธ","๐Ÿ™†๐Ÿฝโ€โ™€๏ธ","๐Ÿ™†๐Ÿพโ€โ™€๏ธ","๐Ÿ™†๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™†","๐Ÿ™†๐Ÿป","๐Ÿ™†๐Ÿผ","๐Ÿ™†๐Ÿฝ","๐Ÿ™†๐Ÿพ","๐Ÿ™†๐Ÿฟ", +"๐Ÿ™†โ€โ™‚๏ธ","๐Ÿ™†๐Ÿปโ€โ™‚๏ธ","๐Ÿ™†๐Ÿผโ€โ™‚๏ธ","๐Ÿ™†๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™†๐Ÿพโ€โ™‚๏ธ","๐Ÿ™†๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™‹โ€โ™€๏ธ","๐Ÿ™‹๐Ÿปโ€โ™€๏ธ","๐Ÿ™‹๐Ÿผโ€โ™€๏ธ","๐Ÿ™‹๐Ÿฝโ€โ™€๏ธ","๐Ÿ™‹๐Ÿพโ€โ™€๏ธ","๐Ÿ™‹๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™‹","๐Ÿ™‹๐Ÿป","๐Ÿ™‹๐Ÿผ","๐Ÿ™‹๐Ÿฝ","๐Ÿ™‹๐Ÿพ","๐Ÿ™‹๐Ÿฟ", +"๐Ÿ™‹โ€โ™‚๏ธ","๐Ÿ™‹๐Ÿปโ€โ™‚๏ธ","๐Ÿ™‹๐Ÿผโ€โ™‚๏ธ","๐Ÿ™‹๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™‹๐Ÿพโ€โ™‚๏ธ","๐Ÿ™‹๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ","๐Ÿง๐Ÿปโ€โ™€๏ธ","๐Ÿง๐Ÿผโ€โ™€๏ธ","๐Ÿง๐Ÿฝโ€โ™€๏ธ","๐Ÿง๐Ÿพโ€โ™€๏ธ","๐Ÿง๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง","๐Ÿง๐Ÿป","๐Ÿง๐Ÿผ","๐Ÿง๐Ÿฝ","๐Ÿง๐Ÿพ","๐Ÿง๐Ÿฟ", +"๐Ÿงโ€โ™‚๏ธ","๐Ÿง๐Ÿปโ€โ™‚๏ธ","๐Ÿง๐Ÿผโ€โ™‚๏ธ","๐Ÿง๐Ÿฝโ€โ™‚๏ธ","๐Ÿง๐Ÿพโ€โ™‚๏ธ","๐Ÿง๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคฆโ€โ™€๏ธ","๐Ÿคฆ๐Ÿปโ€โ™€๏ธ","๐Ÿคฆ๐Ÿผโ€โ™€๏ธ","๐Ÿคฆ๐Ÿฝโ€โ™€๏ธ","๐Ÿคฆ๐Ÿพโ€โ™€๏ธ","๐Ÿคฆ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคฆ","๐Ÿคฆ๐Ÿป","๐Ÿคฆ๐Ÿผ","๐Ÿคฆ๐Ÿฝ","๐Ÿคฆ๐Ÿพ","๐Ÿคฆ๐Ÿฟ", +"๐Ÿคฆโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿปโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿผโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿฝโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿพโ€โ™‚๏ธ","๐Ÿคฆ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคทโ€โ™€๏ธ","๐Ÿคท๐Ÿปโ€โ™€๏ธ","๐Ÿคท๐Ÿผโ€โ™€๏ธ","๐Ÿคท๐Ÿฝโ€โ™€๏ธ","๐Ÿคท๐Ÿพโ€โ™€๏ธ","๐Ÿคท๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคท","๐Ÿคท๐Ÿป","๐Ÿคท๐Ÿผ","๐Ÿคท๐Ÿฝ","๐Ÿคท๐Ÿพ","๐Ÿคท๐Ÿฟ", +"๐Ÿคทโ€โ™‚๏ธ","๐Ÿคท๐Ÿปโ€โ™‚๏ธ","๐Ÿคท๐Ÿผโ€โ™‚๏ธ","๐Ÿคท๐Ÿฝโ€โ™‚๏ธ","๐Ÿคท๐Ÿพโ€โ™‚๏ธ","๐Ÿคท๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™Žโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿปโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿผโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿฝโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿพโ€โ™€๏ธ","๐Ÿ™Ž๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™Ž","๐Ÿ™Ž๐Ÿป","๐Ÿ™Ž๐Ÿผ","๐Ÿ™Ž๐Ÿฝ","๐Ÿ™Ž๐Ÿพ","๐Ÿ™Ž๐Ÿฟ", +"๐Ÿ™Žโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿปโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿผโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿพโ€โ™‚๏ธ","๐Ÿ™Ž๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ™โ€โ™€๏ธ","๐Ÿ™๐Ÿปโ€โ™€๏ธ","๐Ÿ™๐Ÿผโ€โ™€๏ธ","๐Ÿ™๐Ÿฝโ€โ™€๏ธ","๐Ÿ™๐Ÿพโ€โ™€๏ธ","๐Ÿ™๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ™","๐Ÿ™๐Ÿป","๐Ÿ™๐Ÿผ","๐Ÿ™๐Ÿฝ","๐Ÿ™๐Ÿพ","๐Ÿ™๐Ÿฟ", +"๐Ÿ™โ€โ™‚๏ธ","๐Ÿ™๐Ÿปโ€โ™‚๏ธ","๐Ÿ™๐Ÿผโ€โ™‚๏ธ","๐Ÿ™๐Ÿฝโ€โ™‚๏ธ","๐Ÿ™๐Ÿพโ€โ™‚๏ธ","๐Ÿ™๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’‡โ€โ™€๏ธ","๐Ÿ’‡๐Ÿปโ€โ™€๏ธ","๐Ÿ’‡๐Ÿผโ€โ™€๏ธ","๐Ÿ’‡๐Ÿฝโ€โ™€๏ธ","๐Ÿ’‡๐Ÿพโ€โ™€๏ธ","๐Ÿ’‡๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ’‡","๐Ÿ’‡๐Ÿป","๐Ÿ’‡๐Ÿผ","๐Ÿ’‡๐Ÿฝ","๐Ÿ’‡๐Ÿพ","๐Ÿ’‡๐Ÿฟ", +"๐Ÿ’‡โ€โ™‚๏ธ","๐Ÿ’‡๐Ÿปโ€โ™‚๏ธ","๐Ÿ’‡๐Ÿผโ€โ™‚๏ธ","๐Ÿ’‡๐Ÿฝโ€โ™‚๏ธ","๐Ÿ’‡๐Ÿพโ€โ™‚๏ธ","๐Ÿ’‡๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’†โ€โ™€๏ธ","๐Ÿ’†๐Ÿปโ€โ™€๏ธ","๐Ÿ’†๐Ÿผโ€โ™€๏ธ","๐Ÿ’†๐Ÿฝโ€โ™€๏ธ","๐Ÿ’†๐Ÿพโ€โ™€๏ธ","๐Ÿ’†๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ’†","๐Ÿ’†๐Ÿป","๐Ÿ’†๐Ÿผ","๐Ÿ’†๐Ÿฝ","๐Ÿ’†๐Ÿพ","๐Ÿ’†๐Ÿฟ", +"๐Ÿ’†โ€โ™‚๏ธ","๐Ÿ’†๐Ÿปโ€โ™‚๏ธ","๐Ÿ’†๐Ÿผโ€โ™‚๏ธ","๐Ÿ’†๐Ÿฝโ€โ™‚๏ธ","๐Ÿ’†๐Ÿพโ€โ™‚๏ธ","๐Ÿ’†๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿง–โ€โ™€๏ธ","๐Ÿง–๐Ÿปโ€โ™€๏ธ","๐Ÿง–๐Ÿผโ€โ™€๏ธ","๐Ÿง–๐Ÿฝโ€โ™€๏ธ","๐Ÿง–๐Ÿพโ€โ™€๏ธ","๐Ÿง–๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง–","๐Ÿง–๐Ÿป","๐Ÿง–๐Ÿผ","๐Ÿง–๐Ÿฝ","๐Ÿง–๐Ÿพ","๐Ÿง–๐Ÿฟ", +"๐Ÿง–โ€โ™‚๏ธ","๐Ÿง–๐Ÿปโ€โ™‚๏ธ","๐Ÿง–๐Ÿผโ€โ™‚๏ธ","๐Ÿง–๐Ÿฝโ€โ™‚๏ธ","๐Ÿง–๐Ÿพโ€โ™‚๏ธ","๐Ÿง–๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ’…","๐Ÿ’…๐Ÿป","๐Ÿ’…๐Ÿผ","๐Ÿ’…๐Ÿฝ","๐Ÿ’…๐Ÿพ","๐Ÿ’…๐Ÿฟ", +"๐Ÿคณ","๐Ÿคณ๐Ÿป","๐Ÿคณ๐Ÿผ","๐Ÿคณ๐Ÿฝ","๐Ÿคณ๐Ÿพ","๐Ÿคณ๐Ÿฟ", +"๐Ÿ’ƒ","๐Ÿ’ƒ๐Ÿป","๐Ÿ’ƒ๐Ÿผ","๐Ÿ’ƒ๐Ÿฝ","๐Ÿ’ƒ๐Ÿพ","๐Ÿ’ƒ๐Ÿฟ", +"๐Ÿ•บ","๐Ÿ•บ๐Ÿป","๐Ÿ•บ๐Ÿผ","๐Ÿ•บ๐Ÿฝ","๐Ÿ•บ๐Ÿพ","๐Ÿ•บ๐Ÿฟ", +"๐Ÿ‘ฏโ€โ™€๏ธ","๐Ÿ‘ฏ","๐Ÿ‘ฏโ€โ™‚๏ธ", +"๐Ÿ•ด","๐Ÿ•ด๐Ÿป","๐Ÿ•ด๐Ÿผ","๐Ÿ•ด๐Ÿฝ","๐Ÿ•ด๐Ÿพ","๐Ÿ•ด๐Ÿฟ", +"๐Ÿ‘ฉโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฝ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฝ", +"๐Ÿง‘โ€๐Ÿฆฝ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฝ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฝ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฝ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฝ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฝ", +"๐Ÿ‘จโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฝ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฝ", +"๐Ÿ‘ฉโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆผ", +"๐Ÿง‘โ€๐Ÿฆผ","๐Ÿง‘๐Ÿปโ€๐Ÿฆผ","๐Ÿง‘๐Ÿผโ€๐Ÿฆผ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆผ","๐Ÿง‘๐Ÿพโ€๐Ÿฆผ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆผ", +"๐Ÿ‘จโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆผ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆผ", +"๐Ÿšถโ€โ™€๏ธ","๐Ÿšถ๐Ÿปโ€โ™€๏ธ","๐Ÿšถ๐Ÿผโ€โ™€๏ธ","๐Ÿšถ๐Ÿฝโ€โ™€๏ธ","๐Ÿšถ๐Ÿพโ€โ™€๏ธ","๐Ÿšถ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿšถ","๐Ÿšถ๐Ÿป","๐Ÿšถ๐Ÿผ","๐Ÿšถ๐Ÿฝ","๐Ÿšถ๐Ÿพ","๐Ÿšถ๐Ÿฟ", +"๐Ÿšถโ€โ™‚๏ธ","๐Ÿšถ๐Ÿปโ€โ™‚๏ธ","๐Ÿšถ๐Ÿผโ€โ™‚๏ธ","๐Ÿšถ๐Ÿฝโ€โ™‚๏ธ","๐Ÿšถ๐Ÿพโ€โ™‚๏ธ","๐Ÿšถ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฏ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฏ", +"๐Ÿง‘โ€๐Ÿฆฏ","๐Ÿง‘๐Ÿปโ€๐Ÿฆฏ","๐Ÿง‘๐Ÿผโ€๐Ÿฆฏ","๐Ÿง‘๐Ÿฝโ€๐Ÿฆฏ","๐Ÿง‘๐Ÿพโ€๐Ÿฆฏ","๐Ÿง‘๐Ÿฟโ€๐Ÿฆฏ", +"๐Ÿ‘จโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿปโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿผโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿพโ€๐Ÿฆฏ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿฆฏ", +"๐ŸงŽโ€โ™€๏ธ","๐ŸงŽ๐Ÿปโ€โ™€๏ธ","๐ŸงŽ๐Ÿผโ€โ™€๏ธ","๐ŸงŽ๐Ÿฝโ€โ™€๏ธ","๐ŸงŽ๐Ÿพโ€โ™€๏ธ","๐ŸงŽ๐Ÿฟโ€โ™€๏ธ", +"๐ŸงŽ","๐ŸงŽ๐Ÿป","๐ŸงŽ๐Ÿผ","๐ŸงŽ๐Ÿฝ","๐ŸงŽ๐Ÿพ","๐ŸงŽ๐Ÿฟ", +"๐ŸงŽโ€โ™‚๏ธ","๐ŸงŽ๐Ÿปโ€โ™‚๏ธ","๐ŸงŽ๐Ÿผโ€โ™‚๏ธ","๐ŸงŽ๐Ÿฝโ€โ™‚๏ธ","๐ŸงŽ๐Ÿพโ€โ™‚๏ธ","๐ŸงŽ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿƒโ€โ™€๏ธ","๐Ÿƒ๐Ÿปโ€โ™€๏ธ","๐Ÿƒ๐Ÿผโ€โ™€๏ธ","๐Ÿƒ๐Ÿฝโ€โ™€๏ธ","๐Ÿƒ๐Ÿพโ€โ™€๏ธ","๐Ÿƒ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿƒ","๐Ÿƒ๐Ÿป","๐Ÿƒ๐Ÿผ","๐Ÿƒ๐Ÿฝ","๐Ÿƒ๐Ÿพ","๐Ÿƒ๐Ÿฟ", +"๐Ÿƒโ€โ™‚๏ธ","๐Ÿƒ๐Ÿปโ€โ™‚๏ธ","๐Ÿƒ๐Ÿผโ€โ™‚๏ธ","๐Ÿƒ๐Ÿฝโ€โ™‚๏ธ","๐Ÿƒ๐Ÿพโ€โ™‚๏ธ","๐Ÿƒ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ","๐Ÿง๐Ÿปโ€โ™€๏ธ","๐Ÿง๐Ÿผโ€โ™€๏ธ","๐Ÿง๐Ÿฝโ€โ™€๏ธ","๐Ÿง๐Ÿพโ€โ™€๏ธ","๐Ÿง๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง","๐Ÿง๐Ÿป","๐Ÿง๐Ÿผ","๐Ÿง๐Ÿฝ","๐Ÿง๐Ÿพ","๐Ÿง๐Ÿฟ", +"๐Ÿงโ€โ™‚๏ธ","๐Ÿง๐Ÿปโ€โ™‚๏ธ","๐Ÿง๐Ÿผโ€โ™‚๏ธ","๐Ÿง๐Ÿฝโ€โ™‚๏ธ","๐Ÿง๐Ÿพโ€โ™‚๏ธ","๐Ÿง๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‘ซ","๐Ÿ‘ซ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ซ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ซ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ซ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ซ๐Ÿฟ", +"๐Ÿ‘ญ","๐Ÿ‘ญ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ญ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ญ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ญ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ญ๐Ÿฟ", +"๐Ÿ‘ฌ","๐Ÿ‘ฌ๐Ÿป","๐Ÿ‘จ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿปโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฌ๐Ÿผ","๐Ÿ‘จ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿผโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฌ๐Ÿฝ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฝโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฌ๐Ÿพ","๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฟโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฌ๐Ÿฟ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘ฉ๐Ÿฟ", +"๐Ÿ’‘","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿง‘๐Ÿฟ", +"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿป","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿผ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฝ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿพ","๐Ÿ‘ฉ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ๐Ÿฟ", +"๐Ÿ’","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿป","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿผ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฝ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿพ","๐Ÿง‘๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿง‘๐Ÿฟ", +"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿปโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿผโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฝโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿพโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿป","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿผ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฝ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿพ","๐Ÿ‘จ๐Ÿฟโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ๐Ÿฟ", +"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿชข","๐Ÿงถ","๐Ÿงต","๐Ÿชก","๐Ÿงฅ","๐Ÿฅผ","๐Ÿฆบ","๐Ÿ‘š","๐Ÿ‘•","๐Ÿ‘–","๐Ÿฉฒ","๐Ÿฉณ","๐Ÿ‘”","๐Ÿ‘—","๐Ÿ‘™","๐Ÿฉฑ","๐Ÿ‘˜","๐Ÿฅป","๐Ÿฉด","๐Ÿฅฟ","๐Ÿ‘ ","๐Ÿ‘ก","๐Ÿ‘ข","๐Ÿ‘ž","๐Ÿ‘Ÿ","๐Ÿฅพ","๐Ÿงฆ","๐Ÿงค","๐Ÿงฃ","๐ŸŽฉ","๐Ÿงข","๐Ÿ‘’","๐ŸŽ“","โ›‘","๐Ÿช–","๐Ÿ‘‘","๐Ÿ’","๐Ÿ‘","๐Ÿ‘›","๐Ÿ‘œ","๐Ÿ’ผ","๐ŸŽ’","๐Ÿงณ","๐Ÿ‘“","๐Ÿ•ถ","๐Ÿฅฝ","๐ŸŒ‚" + + +"๐Ÿถ","๐Ÿฑ","๐Ÿญ","๐Ÿน","๐Ÿฐ","๐ŸฆŠ","๐Ÿป","๐Ÿผ","๐Ÿปโ€โ„๏ธ","๐Ÿจ","๐Ÿฏ","๐Ÿฆ","๐Ÿฎ","๐Ÿท","๐Ÿฝ","๐Ÿธ","๐Ÿต","๐Ÿ™ˆ","๐Ÿ™‰","๐Ÿ™Š","๐Ÿ’","๐Ÿ”","๐Ÿง","๐Ÿฆ","๐Ÿค","๐Ÿฃ","๐Ÿฅ","๐Ÿฆ†","๐Ÿฆ…","๐Ÿฆ‰","๐Ÿฆ‡","๐Ÿบ","๐Ÿ—","๐Ÿด","๐Ÿฆ„","๐Ÿ","๐Ÿชฑ","๐Ÿ›","๐Ÿฆ‹","๐ŸŒ","๐Ÿž","๐Ÿœ","๐Ÿชฐ","๐Ÿชฒ","๐Ÿชณ","๐ŸฆŸ","๐Ÿฆ—","๐Ÿ•ท","๐Ÿ•ธ","๐Ÿฆ‚","๐Ÿข","๐Ÿ","๐ŸฆŽ","๐Ÿฆ–","๐Ÿฆ•","๐Ÿ™","๐Ÿฆ‘","๐Ÿฆ","๐Ÿฆž","๐Ÿฆ€","๐Ÿก","๐Ÿ ","๐ŸŸ","๐Ÿฌ","๐Ÿณ","๐Ÿ‹","๐Ÿฆˆ","๐Ÿฆญ","๐ŸŠ","๐Ÿ…","๐Ÿ†","๐Ÿฆ“","๐Ÿฆ","๐Ÿฆง","๐Ÿฆฃ","๐Ÿ˜","๐Ÿฆ›","๐Ÿฆ","๐Ÿช","๐Ÿซ","๐Ÿฆ’","๐Ÿฆ˜","๐Ÿฆฌ","๐Ÿƒ","๐Ÿ‚","๐Ÿ„","๐ŸŽ","๐Ÿ–","๐Ÿ","๐Ÿ‘","๐Ÿฆ™","๐Ÿ","๐ŸฆŒ","๐Ÿ•","๐Ÿฉ","๐Ÿฆฎ","๐Ÿ•โ€๐Ÿฆบ","๐Ÿˆ","๐Ÿˆโ€โฌ›","๐Ÿชถ","๐Ÿ“","๐Ÿฆƒ","๐Ÿฆค","๐Ÿฆš","๐Ÿฆœ","๐Ÿฆข","๐Ÿฆฉ","๐Ÿ•Š","๐Ÿ‡","๐Ÿฆ","๐Ÿฆจ","๐Ÿฆก","๐Ÿฆซ","๐Ÿฆฆ","๐Ÿฆฅ","๐Ÿ","๐Ÿ€","๐Ÿฟ","๐Ÿฆ”","๐Ÿพ","๐Ÿ‰","๐Ÿฒ","๐ŸŒต","๐ŸŽ„","๐ŸŒฒ","๐ŸŒณ","๐ŸŒด","๐Ÿชต","๐ŸŒฑ","๐ŸŒฟ","โ˜˜๏ธ","๐Ÿ€","๐ŸŽ","๐Ÿชด","๐ŸŽ‹","๐Ÿƒ","๐Ÿ‚","๐Ÿ","๐Ÿชบ","๐Ÿชน","๐Ÿ„","๐Ÿš","๐Ÿชธ","๐Ÿชจ","๐ŸŒพ","๐Ÿ’","๐ŸŒท","๐ŸŒน","๐Ÿฅ€","๐Ÿชท","๐ŸŒบ","๐ŸŒธ","๐ŸŒผ","๐ŸŒป","๐ŸŒž","๐ŸŒ","๐ŸŒ›","๐ŸŒœ","๐ŸŒš","๐ŸŒ•","๐ŸŒ–","๐ŸŒ—","๐ŸŒ˜","๐ŸŒ‘","๐ŸŒ’","๐ŸŒ“","๐ŸŒ”","๐ŸŒ™","๐ŸŒŽ","๐ŸŒ","๐ŸŒ","๐Ÿช","๐Ÿ’ซ","โญ๏ธ","๐ŸŒŸ","โœจ","โšก๏ธ","โ˜„๏ธ","๐Ÿ’ฅ","๐Ÿ”ฅ","๐ŸŒช","๐ŸŒˆ","โ˜€๏ธ","๐ŸŒค","โ›…๏ธ","๐ŸŒฅ","โ˜๏ธ","๐ŸŒฆ","๐ŸŒง","โ›ˆ","๐ŸŒฉ","๐ŸŒจ","โ„๏ธ","โ˜ƒ๏ธ","โ›„๏ธ","๐ŸŒฌ","๐Ÿ’จ","๐Ÿ’ง","๐Ÿ’ฆ","๐Ÿซง","โ˜”๏ธ","โ˜‚๏ธ","๐ŸŒŠ","๐ŸŒซ" + + +"๐Ÿ","๐ŸŽ","๐Ÿ","๐ŸŠ","๐Ÿ‹","๐ŸŒ","๐Ÿ‰","๐Ÿ‡","๐Ÿ“","๐Ÿซ","๐Ÿˆ","๐Ÿ’","๐Ÿ‘","๐Ÿฅญ","๐Ÿ","๐Ÿฅฅ","๐Ÿฅ","๐Ÿ…","๐Ÿ†","๐Ÿฅ‘","๐Ÿฅฆ","๐Ÿฅฌ","๐Ÿฅ’","๐ŸŒถ","๐Ÿซ‘","๐ŸŒฝ","๐Ÿฅ•","๐Ÿซ’","๐Ÿง„","๐Ÿง…","๐Ÿฅ”","๐Ÿ ","๐Ÿฅ","๐Ÿฅฏ","๐Ÿž","๐Ÿฅ–","๐Ÿฅจ","๐Ÿง€","๐Ÿฅš","๐Ÿณ","๐Ÿงˆ","๐Ÿฅž","๐Ÿง‡","๐Ÿฅ“","๐Ÿฅฉ","๐Ÿ—","๐Ÿ–","๐Ÿฆด","๐ŸŒญ","๐Ÿ”","๐ŸŸ","๐Ÿ•","๐Ÿซ“","๐Ÿฅช","๐Ÿฅ™","๐Ÿง†","๐ŸŒฎ","๐ŸŒฏ","๐Ÿซ”","๐Ÿฅ—","๐Ÿฅ˜","๐Ÿซ•","๐Ÿฅซ","๐Ÿ","๐Ÿœ","๐Ÿฒ","๐Ÿซ™","๐Ÿ›","๐Ÿฃ","๐Ÿฑ","๐ŸฅŸ","๐Ÿฆช","๐Ÿค","๐Ÿ™","๐Ÿš","๐Ÿ˜","๐Ÿฅ","๐Ÿฅ ","๐Ÿฅฎ","๐Ÿข","๐Ÿก","๐Ÿง","๐Ÿจ","๐Ÿฆ","๐Ÿฅง","๐Ÿง","๐Ÿฐ","๐ŸŽ‚","๐Ÿฎ","๐Ÿญ","๐Ÿฌ","๐Ÿซ","๐Ÿฟ","๐Ÿฉ","๐Ÿช","๐ŸŒฐ","๐Ÿฅœ","๐Ÿซ˜","๐Ÿฏ","๐Ÿฅ›","๐Ÿซ—","๐Ÿผ","๐Ÿซ–","โ˜•๏ธ","๐Ÿต","๐Ÿงƒ","๐Ÿฅค","๐Ÿง‹","๐Ÿถ","๐Ÿบ","๐Ÿป","๐Ÿฅ‚","๐Ÿท","๐Ÿฅƒ","๐Ÿธ","๐Ÿน","๐Ÿง‰","๐Ÿพ","๐ŸงŠ","๐Ÿฅ„","๐Ÿด","๐Ÿฝ","๐Ÿฅฃ","๐Ÿฅก","๐Ÿฅข","๐Ÿง‚" + + +"โšฝ๏ธ","๐Ÿ€","๐Ÿˆ","โšพ๏ธ","๐ŸฅŽ","๐ŸŽพ","๐Ÿ","๐Ÿ‰","๐Ÿฅ","๐ŸŽฑ","๐Ÿช€","๐Ÿ“","๐Ÿธ","๐Ÿ’","๐Ÿ‘","๐Ÿฅ","๐Ÿ","๐Ÿชƒ","๐Ÿฅ…","โ›ณ๏ธ","๐Ÿช","๐Ÿ›","๐Ÿน","๐ŸŽฃ","๐Ÿคฟ","๐ŸฅŠ","๐Ÿฅ‹","๐ŸŽฝ","๐Ÿ›น","๐Ÿ›ผ","๐Ÿ›ท","โ›ธ","๐ŸฅŒ","๐ŸŽฟ","โ›ท","๐Ÿ‚","๐Ÿช‚", +"๐Ÿ‹๏ธโ€โ™€๏ธ","๐Ÿ‹๐Ÿปโ€โ™€๏ธ","๐Ÿ‹๐Ÿผโ€โ™€๏ธ","๐Ÿ‹๐Ÿฝโ€โ™€๏ธ","๐Ÿ‹๐Ÿพโ€โ™€๏ธ","๐Ÿ‹๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ‹๏ธ","๐Ÿ‹๐Ÿป","๐Ÿ‹๐Ÿผ","๐Ÿ‹๐Ÿฝ","๐Ÿ‹๐Ÿพ","๐Ÿ‹๐Ÿฟ", +"๐Ÿ‹๏ธโ€โ™‚๏ธ","๐Ÿ‹๐Ÿปโ€โ™‚๏ธ","๐Ÿ‹๐Ÿผโ€โ™‚๏ธ","๐Ÿ‹๐Ÿฝโ€โ™‚๏ธ","๐Ÿ‹๐Ÿพโ€โ™‚๏ธ","๐Ÿ‹๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคผโ€โ™€๏ธ","๐Ÿคผ","๐Ÿคผโ€โ™‚๏ธ", +"๐Ÿคธโ€โ™€๏ธ","๐Ÿคธ๐Ÿปโ€โ™€๏ธ","๐Ÿคธ๐Ÿผโ€โ™€๏ธ","๐Ÿคธ๐Ÿฝโ€โ™€๏ธ","๐Ÿคธ๐Ÿพโ€โ™€๏ธ","๐Ÿคธ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคธ","๐Ÿคธ๐Ÿป","๐Ÿคธ๐Ÿผ","๐Ÿคธ๐Ÿฝ","๐Ÿคธ๐Ÿพ","๐Ÿคธ๐Ÿฟ", +"๐Ÿคธโ€โ™‚๏ธ","๐Ÿคธ๐Ÿปโ€โ™‚๏ธ","๐Ÿคธ๐Ÿผโ€โ™‚๏ธ","๐Ÿคธ๐Ÿฝโ€โ™‚๏ธ","๐Ÿคธ๐Ÿพโ€โ™‚๏ธ","๐Ÿคธ๐Ÿฟโ€โ™‚๏ธ", +"โ›น๏ธโ€โ™€๏ธ","โ›น๐Ÿปโ€โ™€๏ธ","โ›น๐Ÿผโ€โ™€๏ธ","โ›น๐Ÿฝโ€โ™€๏ธ","โ›น๐Ÿพโ€โ™€๏ธ","โ›น๐Ÿฟโ€โ™€๏ธ", +"โ›น๏ธ","โ›น๐Ÿป","โ›น๐Ÿผ","โ›น๐Ÿฝ","โ›น๐Ÿพ","โ›น๐Ÿฟ", +"โ›น๏ธโ€โ™‚๏ธ","โ›น๐Ÿปโ€โ™‚๏ธ","โ›น๐Ÿผโ€โ™‚๏ธ","โ›น๐Ÿฝโ€โ™‚๏ธ","โ›น๐Ÿพโ€โ™‚๏ธ","โ›น๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคบ", +"๐Ÿคพโ€โ™€๏ธ","๐Ÿคพ๐Ÿปโ€โ™€๏ธ","๐Ÿคพ๐Ÿผโ€โ™€๏ธ","๐Ÿคพ๐Ÿฝโ€โ™€๏ธ","๐Ÿคพ๐Ÿพโ€โ™€๏ธ","๐Ÿคพ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคพ","๐Ÿคพ๐Ÿป","๐Ÿคพ๐Ÿผ","๐Ÿคพ๐Ÿฝ","๐Ÿคพ๐Ÿพ","๐Ÿคพ๐Ÿฟ", +"๐Ÿคพโ€โ™‚๏ธ","๐Ÿคพ๐Ÿปโ€โ™‚๏ธ","๐Ÿคพ๐Ÿผโ€โ™‚๏ธ","๐Ÿคพ๐Ÿฝโ€โ™‚๏ธ","๐Ÿคพ๐Ÿพโ€โ™‚๏ธ","๐Ÿคพ๐Ÿฟโ€โ™‚๏ธ", +"๐ŸŒ๏ธโ€โ™€๏ธ","๐ŸŒ๐Ÿปโ€โ™€๏ธ","๐ŸŒ๐Ÿผโ€โ™€๏ธ","๐ŸŒ๐Ÿฝโ€โ™€๏ธ","๐ŸŒ๐Ÿพโ€โ™€๏ธ","๐ŸŒ๐Ÿฟโ€โ™€๏ธ", +"๐ŸŒ๏ธ","๐ŸŒ๐Ÿป","๐ŸŒ๐Ÿผ","๐ŸŒ๐Ÿฝ","๐ŸŒ๐Ÿพ","๐ŸŒ๐Ÿฟ", +"๐ŸŒ๏ธโ€โ™‚๏ธ","๐ŸŒ๐Ÿปโ€โ™‚๏ธ","๐ŸŒ๐Ÿผโ€โ™‚๏ธ","๐ŸŒ๐Ÿฝโ€โ™‚๏ธ","๐ŸŒ๐Ÿพโ€โ™‚๏ธ","๐ŸŒ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ‡","๐Ÿ‡๐Ÿป","๐Ÿ‡๐Ÿผ","๐Ÿ‡๐Ÿฝ","๐Ÿ‡๐Ÿพ","๐Ÿ‡๐Ÿฟ", +"๐Ÿง˜โ€โ™€๏ธ","๐Ÿง˜๐Ÿปโ€โ™€๏ธ","๐Ÿง˜๐Ÿผโ€โ™€๏ธ","๐Ÿง˜๐Ÿฝโ€โ™€๏ธ","๐Ÿง˜๐Ÿพโ€โ™€๏ธ","๐Ÿง˜๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง˜","๐Ÿง˜๐Ÿป","๐Ÿง˜๐Ÿผ","๐Ÿง˜๐Ÿฝ","๐Ÿง˜๐Ÿพ","๐Ÿง˜๐Ÿฟ", +"๐Ÿง˜โ€โ™‚๏ธ","๐Ÿง˜๐Ÿปโ€โ™‚๏ธ","๐Ÿง˜๐Ÿผโ€โ™‚๏ธ","๐Ÿง˜๐Ÿฝโ€โ™‚๏ธ","๐Ÿง˜๐Ÿพโ€โ™‚๏ธ","๐Ÿง˜๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ„โ€โ™€๏ธ","๐Ÿ„๐Ÿปโ€โ™€๏ธ","๐Ÿ„๐Ÿผโ€โ™€๏ธ","๐Ÿ„๐Ÿฝโ€โ™€๏ธ","๐Ÿ„๐Ÿพโ€โ™€๏ธ","๐Ÿ„๐Ÿฟโ€โ™€๏ธ", +"๐Ÿ„","๐Ÿ„๐Ÿป","๐Ÿ„๐Ÿผ","๐Ÿ„๐Ÿฝ","๐Ÿ„๐Ÿพ","๐Ÿ„๐Ÿฟ", +"๐Ÿ„โ€โ™‚๏ธ","๐Ÿ„๐Ÿปโ€โ™‚๏ธ","๐Ÿ„๐Ÿผโ€โ™‚๏ธ","๐Ÿ„๐Ÿฝโ€โ™‚๏ธ","๐Ÿ„๐Ÿพโ€โ™‚๏ธ","๐Ÿ„๐Ÿฟโ€โ™‚๏ธ", +"๐ŸŠโ€โ™€๏ธ","๐ŸŠ๐Ÿปโ€โ™€๏ธ","๐ŸŠ๐Ÿผโ€โ™€๏ธ","๐ŸŠ๐Ÿฝโ€โ™€๏ธ","๐ŸŠ๐Ÿพโ€โ™€๏ธ","๐ŸŠ๐Ÿฟโ€โ™€๏ธ", +"๐ŸŠ","๐ŸŠ๐Ÿป","๐ŸŠ๐Ÿผ","๐ŸŠ๐Ÿฝ","๐ŸŠ๐Ÿพ","๐ŸŠ๐Ÿฟ", +"๐ŸŠโ€โ™‚๏ธ","๐ŸŠ๐Ÿปโ€โ™‚๏ธ","๐ŸŠ๐Ÿผโ€โ™‚๏ธ","๐ŸŠ๐Ÿฝโ€โ™‚๏ธ","๐ŸŠ๐Ÿพโ€โ™‚๏ธ","๐ŸŠ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿคฝโ€โ™€๏ธ","๐Ÿคฝ๐Ÿปโ€โ™€๏ธ","๐Ÿคฝ๐Ÿผโ€โ™€๏ธ","๐Ÿคฝ๐Ÿฝโ€โ™€๏ธ","๐Ÿคฝ๐Ÿพโ€โ™€๏ธ","๐Ÿคฝ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคฝ","๐Ÿคฝ๐Ÿป","๐Ÿคฝ๐Ÿผ","๐Ÿคฝ๐Ÿฝ","๐Ÿคฝ๐Ÿพ","๐Ÿคฝ๐Ÿฟ", +"๐Ÿคฝโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿปโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿผโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿฝโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿพโ€โ™‚๏ธ","๐Ÿคฝ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿšฃโ€โ™€๏ธ","๐Ÿšฃ๐Ÿปโ€โ™€๏ธ","๐Ÿšฃ๐Ÿผโ€โ™€๏ธ","๐Ÿšฃ๐Ÿฝโ€โ™€๏ธ","๐Ÿšฃ๐Ÿพโ€โ™€๏ธ","๐Ÿšฃ๐Ÿฟโ€โ™€๏ธ", +"๐Ÿšฃ","๐Ÿšฃ๐Ÿป","๐Ÿšฃ๐Ÿผ","๐Ÿšฃ๐Ÿฝ","๐Ÿšฃ๐Ÿพ","๐Ÿšฃ๐Ÿฟ", +"๐Ÿšฃโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿปโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿผโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿฝโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿพโ€โ™‚๏ธ","๐Ÿšฃ๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿง—โ€โ™€๏ธ","๐Ÿง—๐Ÿปโ€โ™€๏ธ","๐Ÿง—๐Ÿผโ€โ™€๏ธ","๐Ÿง—๐Ÿฝโ€โ™€๏ธ","๐Ÿง—๐Ÿพโ€โ™€๏ธ","๐Ÿง—๐Ÿฟโ€โ™€๏ธ", +"๐Ÿง—","๐Ÿง—๐Ÿป","๐Ÿง—๐Ÿผ","๐Ÿง—๐Ÿฝ","๐Ÿง—๐Ÿพ","๐Ÿง—๐Ÿฟ", +"๐Ÿง—โ€โ™‚๏ธ","๐Ÿง—๐Ÿปโ€โ™‚๏ธ","๐Ÿง—๐Ÿผโ€โ™‚๏ธ","๐Ÿง—๐Ÿฝโ€โ™‚๏ธ","๐Ÿง—๐Ÿพโ€โ™‚๏ธ","๐Ÿง—๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿšตโ€โ™€๏ธ","๐Ÿšต๐Ÿปโ€โ™€๏ธ","๐Ÿšต๐Ÿผโ€โ™€๏ธ","๐Ÿšต๐Ÿฝโ€โ™€๏ธ","๐Ÿšต๐Ÿพโ€โ™€๏ธ","๐Ÿšต๐Ÿฟโ€โ™€๏ธ", +"๐Ÿšต","๐Ÿšต๐Ÿป","๐Ÿšต๐Ÿผ","๐Ÿšต๐Ÿฝ","๐Ÿšต๐Ÿพ","๐Ÿšต๐Ÿฟ", +"๐Ÿšตโ€โ™‚๏ธ","๐Ÿšต๐Ÿปโ€โ™‚๏ธ","๐Ÿšต๐Ÿผโ€โ™‚๏ธ","๐Ÿšต๐Ÿฝโ€โ™‚๏ธ","๐Ÿšต๐Ÿพโ€โ™‚๏ธ","๐Ÿšต๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿšดโ€โ™€๏ธ","๐Ÿšด๐Ÿปโ€โ™€๏ธ","๐Ÿšด๐Ÿผโ€โ™€๏ธ","๐Ÿšด๐Ÿฝโ€โ™€๏ธ","๐Ÿšด๐Ÿพโ€โ™€๏ธ","๐Ÿšด๐Ÿฟโ€โ™€๏ธ", +"๐Ÿšด","๐Ÿšด๐Ÿป","๐Ÿšด๐Ÿผ","๐Ÿšด๐Ÿฝ","๐Ÿšด๐Ÿพ","๐Ÿšด๐Ÿฟ", +"๐Ÿšดโ€โ™‚๏ธ","๐Ÿšด๐Ÿปโ€โ™‚๏ธ","๐Ÿšด๐Ÿผโ€โ™‚๏ธ","๐Ÿšด๐Ÿฝโ€โ™‚๏ธ","๐Ÿšด๐Ÿพโ€โ™‚๏ธ","๐Ÿšด๐Ÿฟโ€โ™‚๏ธ", +"๐Ÿ†","๐Ÿฅ‡","๐Ÿฅˆ","๐Ÿฅ‰","๐Ÿ…","๐ŸŽ–","๐Ÿต","๐ŸŽ—","๐ŸŽซ","๐ŸŽŸ","๐ŸŽช", +"๐Ÿคนโ€โ™€๏ธ","๐Ÿคน๐Ÿปโ€โ™€๏ธ","๐Ÿคน๐Ÿผโ€โ™€๏ธ","๐Ÿคน๐Ÿฝโ€โ™€๏ธ","๐Ÿคน๐Ÿพโ€โ™€๏ธ","๐Ÿคน๐Ÿฟโ€โ™€๏ธ", +"๐Ÿคน","๐Ÿคน๐Ÿป","๐Ÿคน๐Ÿผ","๐Ÿคน๐Ÿฝ","๐Ÿคน๐Ÿพ","๐Ÿคน๐Ÿฟ", +"๐Ÿคนโ€โ™‚๏ธ","๐Ÿคน๐Ÿปโ€โ™‚๏ธ","๐Ÿคน๐Ÿผโ€โ™‚๏ธ","๐Ÿคน๐Ÿฝโ€โ™‚๏ธ","๐Ÿคน๐Ÿพโ€โ™‚๏ธ","๐Ÿคน๐Ÿฟโ€โ™‚๏ธ", +"๐ŸŽญ","๐Ÿฉฐ","๐ŸŽจ","๐ŸŽฌ","๐ŸŽค","๐ŸŽง","๐ŸŽผ","๐ŸŽน","๐Ÿฅ","๐Ÿช˜","๐ŸŽท","๐ŸŽบ","๐Ÿช—","๐ŸŽธ","๐Ÿช•","๐ŸŽป","๐ŸŽฒ","โ™Ÿ","๐ŸŽฏ","๐ŸŽณ","๐ŸŽฎ","๐ŸŽฐ","๐Ÿงฉ" + + +"๐Ÿš—","๐Ÿš•","๐Ÿš™","๐ŸšŒ","๐ŸšŽ","๐ŸŽ","๐Ÿš“","๐Ÿš‘","๐Ÿš’","๐Ÿš","๐Ÿ›ป","๐Ÿšš","๐Ÿš›","๐Ÿšœ","๐Ÿฆฏ","๐Ÿฆฝ","๐Ÿฆผ","๐Ÿฉผ","๐Ÿ›ด","๐Ÿšฒ","๐Ÿ›ต","๐Ÿ","๐Ÿ›บ","๐Ÿ›ž","๐Ÿšจ","๐Ÿš”","๐Ÿš","๐Ÿš˜","๐Ÿš–","๐Ÿšก","๐Ÿš ","๐ŸšŸ","๐Ÿšƒ","๐Ÿš‹","๐Ÿšž","๐Ÿš","๐Ÿš„","๐Ÿš…","๐Ÿšˆ","๐Ÿš‚","๐Ÿš†","๐Ÿš‡","๐ŸšŠ","๐Ÿš‰","โœˆ๏ธ","๐Ÿ›ซ","๐Ÿ›ฌ","๐Ÿ›ฉ","๐Ÿ’บ","๐Ÿ›ฐ","๐Ÿš€","๐Ÿ›ธ","๐Ÿš","๐Ÿ›ถ","โ›ต๏ธ","๐Ÿšค","๐Ÿ›ฅ","๐Ÿ›ณ","โ›ด","๐Ÿšข","๐Ÿ›Ÿ","โš“๏ธ","๐Ÿช","โ›ฝ๏ธ","๐Ÿšง","๐Ÿšฆ","๐Ÿšฅ","๐Ÿš","๐Ÿ—บ","๐Ÿ—ฟ","๐Ÿ—ฝ","๐Ÿ—ผ","๐Ÿฐ","๐Ÿฏ","๐ŸŸ","๐ŸŽก","๐ŸŽข","๐ŸŽ ","โ›ฒ๏ธ","โ›ฑ","๐Ÿ–","๐Ÿ","๐Ÿœ","๐ŸŒ‹","โ›ฐ","๐Ÿ”","๐Ÿ—ป","๐Ÿ•","โ›บ๏ธ","๐Ÿ›–","๐Ÿ ","๐Ÿก","๐Ÿ˜","๐Ÿš","๐Ÿ—","๐Ÿญ","๐Ÿข","๐Ÿฌ","๐Ÿฃ","๐Ÿค","๐Ÿฅ","๐Ÿฆ","๐Ÿจ","๐Ÿช","๐Ÿซ","๐Ÿฉ","๐Ÿ’’","๐Ÿ›","โ›ช๏ธ","๐Ÿ•Œ","๐Ÿ•","๐Ÿ›•","๐Ÿ•‹","โ›ฉ","๐Ÿ›ค","๐Ÿ›ฃ","๐Ÿ—พ","๐ŸŽ‘","๐Ÿž","๐ŸŒ…","๐ŸŒ„","๐ŸŒ ","๐ŸŽ‡","๐ŸŽ†","๐ŸŒ‡","๐ŸŒ†","๐Ÿ™","๐ŸŒƒ","๐ŸŒŒ","๐ŸŒ‰","๐ŸŒ" + + + +"โŒš๏ธ","๐Ÿ“ฑ","๐Ÿ“ฒ","๐Ÿ’ป","โŒจ๏ธ","๐Ÿ–ฅ","๐Ÿ–จ","๐Ÿ–ฑ","๐Ÿ–ฒ","๐Ÿ•น","๐Ÿ—œ","๐Ÿ’ฝ","๐Ÿ’พ","๐Ÿ’ฟ","๐Ÿ“€","๐Ÿ“ผ","๐Ÿ“ท","๐Ÿ“ธ","๐Ÿ“น","๐ŸŽฅ","๐Ÿ“ฝ","๐ŸŽž","๐Ÿ“ž","โ˜Ž๏ธ","๐Ÿ“Ÿ","๐Ÿ“ ","๐Ÿ“บ","๐Ÿ“ป","๐ŸŽ™","๐ŸŽš","๐ŸŽ›","๐Ÿงญ","โฑ","โฒ","โฐ","๐Ÿ•ฐ","โŒ›๏ธ","โณ","๐Ÿ“ก","๐Ÿ”‹","๐Ÿชซ","๐Ÿ”Œ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ•ฏ","๐Ÿช”","๐Ÿงฏ","๐Ÿ›ข","๐Ÿ’ธ","๐Ÿ’ต","๐Ÿ’ด","๐Ÿ’ถ","๐Ÿ’ท","๐Ÿช™","๐Ÿ’ฐ","๐Ÿ’ณ","๐Ÿชช","๐Ÿ’Ž","โš–๏ธ","๐Ÿชœ","๐Ÿงฐ","๐Ÿช›","๐Ÿ”ง","๐Ÿ”จ","โš’","๐Ÿ› ","โ›","๐Ÿชš","๐Ÿ”ฉ","โš™๏ธ","๐Ÿชค","๐Ÿงฑ","โ›“","๐Ÿงฒ","๐Ÿ”ซ","๐Ÿ’ฃ","๐Ÿงจ","๐Ÿช“","๐Ÿ”ช","๐Ÿ—ก","โš”๏ธ","๐Ÿ›ก","๐Ÿšฌ","โšฐ๏ธ","๐Ÿชฆ","โšฑ๏ธ","๐Ÿบ","๐Ÿ”ฎ","๐Ÿ“ฟ","๐Ÿงฟ","๐Ÿชฌ","๐Ÿ’ˆ","โš—๏ธ","๐Ÿ”ญ","๐Ÿ”ฌ","๐Ÿ•ณ","๐Ÿฉป","๐Ÿฉน","๐Ÿฉบ","๐Ÿ’Š","๐Ÿ’‰","๐Ÿฉธ","๐Ÿงฌ","๐Ÿฆ ","๐Ÿงซ","๐Ÿงช","๐ŸŒก","๐Ÿงน","๐Ÿช ","๐Ÿงบ","๐Ÿงป","๐Ÿšฝ","๐Ÿšฐ","๐Ÿšฟ","๐Ÿ›", +"๐Ÿ›€","๐Ÿ›€๐Ÿป","๐Ÿ›€๐Ÿผ","๐Ÿ›€๐Ÿฝ","๐Ÿ›€๐Ÿพ","๐Ÿ›€๐Ÿฟ", +"๐Ÿงผ","๐Ÿชฅ","๐Ÿช’","๐Ÿงฝ","๐Ÿชฃ","๐Ÿงด","๐Ÿ›Ž","๐Ÿ”‘","๐Ÿ—","๐Ÿšช","๐Ÿช‘","๐Ÿ›‹","๐Ÿ›","๐Ÿ›Œ","๐Ÿงธ","๐Ÿช†","๐Ÿ–ผ","๐Ÿชž","๐ŸชŸ","๐Ÿ›","๐Ÿ›’","๐ŸŽ","๐ŸŽˆ","๐ŸŽ","๐ŸŽ€","๐Ÿช„","๐Ÿช…","๐ŸŽŠ","๐ŸŽ‰","๐ŸŽŽ","๐Ÿฎ","๐ŸŽ","๐Ÿชฉ","๐Ÿงง","โœ‰๏ธ","๐Ÿ“ฉ","๐Ÿ“จ","๐Ÿ“ง","๐Ÿ’Œ","๐Ÿ“ฅ","๐Ÿ“ค","๐Ÿ“ฆ","๐Ÿท","๐Ÿชง","๐Ÿ“ช","๐Ÿ“ซ","๐Ÿ“ฌ","๐Ÿ“ญ","๐Ÿ“ฎ","๐Ÿ“ฏ","๐Ÿ“œ","๐Ÿ“ƒ","๐Ÿ“„","๐Ÿ“‘","๐Ÿงพ","๐Ÿ“Š","๐Ÿ“ˆ","๐Ÿ“‰","๐Ÿ—’","๐Ÿ—“","๐Ÿ“†","๐Ÿ“…","๐Ÿ—‘","๐Ÿ“‡","๐Ÿ—ƒ","๐Ÿ—ณ","๐Ÿ—„","๐Ÿ“‹","๐Ÿ“","๐Ÿ“‚","๐Ÿ—‚","๐Ÿ—ž","๐Ÿ“ฐ","๐Ÿ““","๐Ÿ“”","๐Ÿ“’","๐Ÿ“•","๐Ÿ“—","๐Ÿ“˜","๐Ÿ“™","๐Ÿ“š","๐Ÿ“–","๐Ÿ”–","๐Ÿงท","๐Ÿ”—","๐Ÿ“Ž","๐Ÿ–‡","๐Ÿ“","๐Ÿ“","๐Ÿงฎ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ–Š","๐Ÿ–‹","โœ’๏ธ","๐Ÿ–Œ","๐Ÿ–","๐Ÿ“","โœ๏ธ","๐Ÿ”","๐Ÿ”Ž","๐Ÿ”","๐Ÿ”","๐Ÿ”’","๐Ÿ”“" + + + +"โค๏ธ","๐Ÿงก","๐Ÿ’›","๐Ÿ’š","๐Ÿ’™","๐Ÿ’œ","๐Ÿ–ค","๐Ÿค","๐ŸคŽ","๐Ÿ’”","โค๏ธโ€๐Ÿ”ฅ","โค๏ธโ€๐Ÿฉน","โฃ๏ธ","๐Ÿ’•","๐Ÿ’ž","๐Ÿ’“","๐Ÿ’—","๐Ÿ’–","๐Ÿ’˜","๐Ÿ’","๐Ÿ’Ÿ","โ˜ฎ๏ธ","โœ๏ธ","โ˜ช๏ธ","๐Ÿ•‰","โ˜ธ๏ธ","โœก๏ธ","๐Ÿ”ฏ","๐Ÿ•Ž","โ˜ฏ๏ธ","โ˜ฆ๏ธ","๐Ÿ›","โ›Ž","โ™ˆ๏ธ","โ™‰๏ธ","โ™Š๏ธ","โ™‹๏ธ","โ™Œ๏ธ","โ™๏ธ","โ™Ž๏ธ","โ™๏ธ","โ™๏ธ","โ™‘๏ธ","โ™’๏ธ","โ™“๏ธ","๐Ÿ†”","โš›๏ธ","๐Ÿ‰‘","โ˜ข๏ธ","โ˜ฃ๏ธ","๐Ÿ“ด","๐Ÿ“ณ","๐Ÿˆถ","๐Ÿˆš๏ธ","๐Ÿˆธ","๐Ÿˆบ","๐Ÿˆท๏ธ","โœด๏ธ","๐Ÿ†š","๐Ÿ’ฎ","๐Ÿ‰","ใŠ™๏ธ","ใŠ—๏ธ","๐Ÿˆด","๐Ÿˆต","๐Ÿˆน","๐Ÿˆฒ","๐Ÿ…ฐ๏ธ","๐Ÿ…ฑ๏ธ","๐Ÿ†Ž","๐Ÿ†‘","๐Ÿ…พ๏ธ","๐Ÿ†˜","โŒ","โญ•๏ธ","๐Ÿ›‘","โ›”๏ธ","๐Ÿ“›","๐Ÿšซ","๐Ÿ’ฏ","๐Ÿ’ข","โ™จ๏ธ","๐Ÿšท","๐Ÿšฏ","๐Ÿšณ","๐Ÿšฑ","๐Ÿ”ž","๐Ÿ“ต","๐Ÿšญ","โ—๏ธ","โ•","โ“","โ”","โ€ผ๏ธ","โ‰๏ธ","๐Ÿ”…","๐Ÿ”†","ใ€ฝ๏ธ","โš ๏ธ","๐Ÿšธ","๐Ÿ”ฑ","โšœ๏ธ","๐Ÿ”ฐ","โ™ป๏ธ","โœ…","๐Ÿˆฏ๏ธ","๐Ÿ’น","โ‡๏ธ","โœณ๏ธ","โŽ","๐ŸŒ","๐Ÿ’ ","โ“‚๏ธ","๐ŸŒ€","๐Ÿ’ค","๐Ÿง","๐Ÿšพ","โ™ฟ๏ธ","๐Ÿ…ฟ๏ธ","๐Ÿ›—","๐Ÿˆณ","๐Ÿˆ‚๏ธ","๐Ÿ›‚","๐Ÿ›ƒ","๐Ÿ›„","๐Ÿ›…","๐Ÿšน","๐Ÿšบ","๐Ÿšผ","โšง","๐Ÿšป","๐Ÿšฎ","๐ŸŽฆ","๐Ÿ“ถ","๐Ÿˆ","๐Ÿ”ฃ","โ„น๏ธ","๐Ÿ”ค","๐Ÿ”ก","๐Ÿ” ","๐Ÿ†–","๐Ÿ†—","๐Ÿ†™","๐Ÿ†’","๐Ÿ†•","๐Ÿ†“","0๏ธโƒฃ","1๏ธโƒฃ","2๏ธโƒฃ","3๏ธโƒฃ","4๏ธโƒฃ","5๏ธโƒฃ","6๏ธโƒฃ","7๏ธโƒฃ","8๏ธโƒฃ","9๏ธโƒฃ","๐Ÿ”Ÿ","๐Ÿ”ข","#๏ธโƒฃ","*๏ธโƒฃ","โ๏ธ","โ–ถ๏ธ","โธ","โฏ","โน","โบ","โญ","โฎ","โฉ","โช","โซ","โฌ","โ—€๏ธ","๐Ÿ”ผ","๐Ÿ”ฝ","โžก๏ธ","โฌ…๏ธ","โฌ†๏ธ","โฌ‡๏ธ","โ†—๏ธ","โ†˜๏ธ","โ†™๏ธ","โ†–๏ธ","โ†•๏ธ","โ†”๏ธ","โ†ช๏ธ","โ†ฉ๏ธ","โคด๏ธ","โคต๏ธ","๐Ÿ”€","๐Ÿ”","๐Ÿ”‚","๐Ÿ”„","๐Ÿ”ƒ","๐ŸŽต","๐ŸŽถ","โž•","โž–","โž—", "โœ–๏ธ", "๐ŸŸฐ", "โ™พ", "๐Ÿ’ฒ","๐Ÿ’ฑ","โ„ข๏ธ","ยฉ๏ธ","ยฎ๏ธ","๐Ÿ‘โ€๐Ÿ—จ","๐Ÿ”š","๐Ÿ”™","๐Ÿ”›","๐Ÿ”","๐Ÿ”œ","ใ€ฐ๏ธ","โžฐ","โžฟ","โœ”๏ธ","โ˜‘๏ธ","๐Ÿ”˜","๐Ÿ”ด","๐ŸŸ ","๐ŸŸก","๐ŸŸข","๐Ÿ”ต","๐ŸŸฃ","โšซ๏ธ","โšช๏ธ","๐ŸŸค","๐Ÿ”บ","๐Ÿ”ป","๐Ÿ”ธ","๐Ÿ”น","๐Ÿ”ถ","๐Ÿ”ท","๐Ÿ”ณ","๐Ÿ”ฒ","โ–ช๏ธ","โ–ซ๏ธ","โ—พ๏ธ","โ—ฝ๏ธ","โ—ผ๏ธ","โ—ป๏ธ","๐ŸŸฅ","๐ŸŸง","๐ŸŸจ","๐ŸŸฉ","๐ŸŸฆ","๐ŸŸช","โฌ›๏ธ","โฌœ๏ธ","๐ŸŸซ","๐Ÿ”ˆ","๐Ÿ”‡","๐Ÿ”‰","๐Ÿ”Š","๐Ÿ””","๐Ÿ”•","๐Ÿ“ฃ","๐Ÿ“ข","๐Ÿ’ฌ","๐Ÿ’ญ","๐Ÿ—ฏ","โ™ ๏ธ","โ™ฃ๏ธ","โ™ฅ๏ธ","โ™ฆ๏ธ","๐Ÿƒ","๐ŸŽด","๐Ÿ€„๏ธ","๐Ÿ•","๐Ÿ•‘","๐Ÿ•’","๐Ÿ•“","๐Ÿ•”","๐Ÿ••","๐Ÿ•–","๐Ÿ•—","๐Ÿ•˜","๐Ÿ•™","๐Ÿ•š","๐Ÿ•›","๐Ÿ•œ","๐Ÿ•","๐Ÿ•ž","๐Ÿ•Ÿ","๐Ÿ• ","๐Ÿ•ก","๐Ÿ•ข","๐Ÿ•ฃ","๐Ÿ•ค","๐Ÿ•ฅ","๐Ÿ•ฆ","๐Ÿ•ง" + + +"๐Ÿณ๏ธ","๐Ÿด","๐Ÿดโ€โ˜ ๏ธ","๐Ÿ","๐Ÿšฉ","๐Ÿณ๏ธโ€๐ŸŒˆ","๐Ÿณ๏ธโ€โšง๏ธ","๐Ÿ‡บ๐Ÿ‡ณ","๐Ÿ‡ฆ๐Ÿ‡ซ","๐Ÿ‡ฆ๐Ÿ‡ฝ","๐Ÿ‡ฆ๐Ÿ‡ฑ","๐Ÿ‡ฉ๐Ÿ‡ฟ","๐Ÿ‡ฆ๐Ÿ‡ธ","๐Ÿ‡ฆ๐Ÿ‡ฉ","๐Ÿ‡ฆ๐Ÿ‡ด","๐Ÿ‡ฆ๐Ÿ‡ฎ","๐Ÿ‡ฆ๐Ÿ‡ถ","๐Ÿ‡ฆ๐Ÿ‡ฌ","๐Ÿ‡ฆ๐Ÿ‡ท","๐Ÿ‡ฆ๐Ÿ‡ฒ","๐Ÿ‡ฆ๐Ÿ‡ผ","๐Ÿ‡ฆ๐Ÿ‡บ","๐Ÿ‡ฆ๐Ÿ‡น","๐Ÿ‡ฆ๐Ÿ‡ฟ","๐Ÿ‡ง๐Ÿ‡ธ","๐Ÿ‡ง๐Ÿ‡ญ","๐Ÿ‡ง๐Ÿ‡ฉ","๐Ÿ‡ง๐Ÿ‡ง","๐Ÿ‡ง๐Ÿ‡พ","๐Ÿ‡ง๐Ÿ‡ช","๐Ÿ‡ง๐Ÿ‡ฟ","๐Ÿ‡ง๐Ÿ‡ฏ","๐Ÿ‡ง๐Ÿ‡ฒ","๐Ÿ‡ง๐Ÿ‡น","๐Ÿ‡ง๐Ÿ‡ด","๐Ÿ‡ง๐Ÿ‡ฆ","๐Ÿ‡ง๐Ÿ‡ผ","๐Ÿ‡ง๐Ÿ‡ท","๐Ÿ‡ป๐Ÿ‡ฌ","๐Ÿ‡ง๐Ÿ‡ณ","๐Ÿ‡ง๐Ÿ‡ฌ","๐Ÿ‡ง๐Ÿ‡ซ","๐Ÿ‡ง๐Ÿ‡ฎ","๐Ÿ‡ฐ๐Ÿ‡ญ","๐Ÿ‡จ๐Ÿ‡ฒ","๐Ÿ‡จ๐Ÿ‡ฆ","๐Ÿ‡ฎ๐Ÿ‡จ","๐Ÿ‡จ๐Ÿ‡ป","๐Ÿ‡ง๐Ÿ‡ถ","๐Ÿ‡ฐ๐Ÿ‡พ","๐Ÿ‡จ๐Ÿ‡ซ","๐Ÿ‡น๐Ÿ‡ฉ","๐Ÿ‡ฎ๐Ÿ‡ด","๐Ÿ‡จ๐Ÿ‡ฑ","๐Ÿ‡จ๐Ÿ‡ณ","๐Ÿ‡จ๐Ÿ‡ฝ","๐Ÿ‡จ๐Ÿ‡จ","๐Ÿ‡จ๐Ÿ‡ด","๐Ÿ‡ฐ๐Ÿ‡ฒ","๐Ÿ‡จ๐Ÿ‡ฌ","๐Ÿ‡จ๐Ÿ‡ฉ","๐Ÿ‡จ๐Ÿ‡ฐ","๐Ÿ‡จ๐Ÿ‡ท","๐Ÿ‡จ๐Ÿ‡ฎ","๐Ÿ‡ญ๐Ÿ‡ท","๐Ÿ‡จ๐Ÿ‡บ","๐Ÿ‡จ๐Ÿ‡ผ","๐Ÿ‡จ๐Ÿ‡พ","๐Ÿ‡จ๐Ÿ‡ฟ","๐Ÿ‡ฉ๐Ÿ‡ฐ","๐Ÿ‡ฉ๐Ÿ‡ฏ","๐Ÿ‡ฉ๐Ÿ‡ฒ","๐Ÿ‡ฉ๐Ÿ‡ด","๐Ÿ‡ช๐Ÿ‡จ","๐Ÿ‡ช๐Ÿ‡ฌ","๐Ÿ‡ธ๐Ÿ‡ป","๐Ÿ‡ฌ๐Ÿ‡ถ","๐Ÿ‡ช๐Ÿ‡ท","๐Ÿ‡ช๐Ÿ‡ช","๐Ÿ‡ธ๐Ÿ‡ฟ","๐Ÿ‡ช๐Ÿ‡น","๐Ÿ‡ช๐Ÿ‡บ","๐Ÿ‡ซ๐Ÿ‡ฐ","๐Ÿ‡ซ๐Ÿ‡ด","๐Ÿ‡ซ๐Ÿ‡ฏ","๐Ÿ‡ซ๐Ÿ‡ฎ","๐Ÿ‡ซ๐Ÿ‡ท","๐Ÿ‡ฌ๐Ÿ‡ซ","๐Ÿ‡ต๐Ÿ‡ซ","๐Ÿ‡น๐Ÿ‡ซ","๐Ÿ‡ฌ๐Ÿ‡ฆ","๐Ÿ‡ฌ๐Ÿ‡ฒ","๐Ÿ‡ฌ๐Ÿ‡ช","๐Ÿ‡ฉ๐Ÿ‡ช","๐Ÿ‡ฌ๐Ÿ‡ญ","๐Ÿ‡ฌ๐Ÿ‡ฎ","๐Ÿ‡ฌ๐Ÿ‡ท","๐Ÿ‡ฌ๐Ÿ‡ฑ","๐Ÿ‡ฌ๐Ÿ‡ฉ","๐Ÿ‡ฌ๐Ÿ‡ต","๐Ÿ‡ฌ๐Ÿ‡บ","๐Ÿ‡ฌ๐Ÿ‡น","๐Ÿ‡ฌ๐Ÿ‡ฌ","๐Ÿ‡ฌ๐Ÿ‡ณ","๐Ÿ‡ฌ๐Ÿ‡ผ","๐Ÿ‡ฌ๐Ÿ‡พ","๐Ÿ‡ญ๐Ÿ‡น","๐Ÿ‡ญ๐Ÿ‡ณ","๐Ÿ‡ญ๐Ÿ‡ฐ","๐Ÿ‡ญ๐Ÿ‡บ","๐Ÿ‡ฎ๐Ÿ‡ธ","๐Ÿ‡ฎ๐Ÿ‡ณ","๐Ÿ‡ฎ๐Ÿ‡ฉ","๐Ÿ‡ฎ๐Ÿ‡ท","๐Ÿ‡ฎ๐Ÿ‡ถ","๐Ÿ‡ฎ๐Ÿ‡ช","๐Ÿ‡ฎ๐Ÿ‡ฒ","๐Ÿ‡ฎ๐Ÿ‡ฑ","๐Ÿ‡ฎ๐Ÿ‡น","๐Ÿ‡ฏ๐Ÿ‡ฒ","๐Ÿ‡ฏ๐Ÿ‡ต","๐ŸŽŒ","๐Ÿ‡ฏ๐Ÿ‡ช","๐Ÿ‡ฏ๐Ÿ‡ด","๐Ÿ‡ฐ๐Ÿ‡ฟ","๐Ÿ‡ฐ๐Ÿ‡ช","๐Ÿ‡ฐ๐Ÿ‡ฎ","๐Ÿ‡ฝ๐Ÿ‡ฐ","๐Ÿ‡ฐ๐Ÿ‡ผ","๐Ÿ‡ฐ๐Ÿ‡ฌ","๐Ÿ‡ฑ๐Ÿ‡ฆ","๐Ÿ‡ฑ๐Ÿ‡ป","๐Ÿ‡ฑ๐Ÿ‡ง","๐Ÿ‡ฑ๐Ÿ‡ธ","๐Ÿ‡ฑ๐Ÿ‡ท","๐Ÿ‡ฑ๐Ÿ‡พ","๐Ÿ‡ฑ๐Ÿ‡ฎ","๐Ÿ‡ฑ๐Ÿ‡น","๐Ÿ‡ฑ๐Ÿ‡บ","๐Ÿ‡ฒ๐Ÿ‡ด","๐Ÿ‡ฒ๐Ÿ‡ฌ","๐Ÿ‡ฒ๐Ÿ‡ผ","๐Ÿ‡ฒ๐Ÿ‡พ","๐Ÿ‡ฒ๐Ÿ‡ป","๐Ÿ‡ฒ๐Ÿ‡ฑ","๐Ÿ‡ฒ๐Ÿ‡น","๐Ÿ‡ฒ๐Ÿ‡ญ","๐Ÿ‡ฒ๐Ÿ‡ถ","๐Ÿ‡ฒ๐Ÿ‡ท","๐Ÿ‡ฒ๐Ÿ‡บ","๐Ÿ‡พ๐Ÿ‡น","๐Ÿ‡ฒ๐Ÿ‡ฝ","๐Ÿ‡ซ๐Ÿ‡ฒ","๐Ÿ‡ฒ๐Ÿ‡ฉ","๐Ÿ‡ฒ๐Ÿ‡จ","๐Ÿ‡ฒ๐Ÿ‡ณ","๐Ÿ‡ฒ๐Ÿ‡ช","๐Ÿ‡ฒ๐Ÿ‡ธ","๐Ÿ‡ฒ๐Ÿ‡ฆ","๐Ÿ‡ฒ๐Ÿ‡ฟ","๐Ÿ‡ฒ๐Ÿ‡ฒ","๐Ÿ‡ณ๐Ÿ‡ฆ","๐Ÿ‡ณ๐Ÿ‡ท","๐Ÿ‡ณ๐Ÿ‡ต","๐Ÿ‡ณ๐Ÿ‡ฑ","๐Ÿ‡ณ๐Ÿ‡จ","๐Ÿ‡ณ๐Ÿ‡ฟ","๐Ÿ‡ณ๐Ÿ‡ฎ","๐Ÿ‡ณ๐Ÿ‡ช","๐Ÿ‡ณ๐Ÿ‡ฌ","๐Ÿ‡ณ๐Ÿ‡บ","๐Ÿ‡ณ๐Ÿ‡ซ","๐Ÿ‡ฐ๐Ÿ‡ต","๐Ÿ‡ฒ๐Ÿ‡ฐ","๐Ÿ‡ฒ๐Ÿ‡ต","๐Ÿ‡ณ๐Ÿ‡ด","๐Ÿ‡ด๐Ÿ‡ฒ","๐Ÿ‡ต๐Ÿ‡ฐ","๐Ÿ‡ต๐Ÿ‡ผ","๐Ÿ‡ต๐Ÿ‡ธ","๐Ÿ‡ต๐Ÿ‡ฆ","๐Ÿ‡ต๐Ÿ‡ฌ","๐Ÿ‡ต๐Ÿ‡พ","๐Ÿ‡ต๐Ÿ‡ช","๐Ÿ‡ต๐Ÿ‡ญ","๐Ÿ‡ต๐Ÿ‡ณ","๐Ÿ‡ต๐Ÿ‡ฑ","๐Ÿ‡ต๐Ÿ‡น","๐Ÿ‡ต๐Ÿ‡ท","๐Ÿ‡ถ๐Ÿ‡ฆ","๐Ÿ‡ท๐Ÿ‡ช","๐Ÿ‡ท๐Ÿ‡ด","๐Ÿ‡ท๐Ÿ‡บ","๐Ÿ‡ท๐Ÿ‡ผ","๐Ÿ‡ผ๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡ฒ","๐Ÿ‡ธ๐Ÿ‡น","๐Ÿ‡ธ๐Ÿ‡ฆ","๐Ÿ‡ธ๐Ÿ‡ณ","๐Ÿ‡ท๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡จ","๐Ÿ‡ธ๐Ÿ‡ฑ","๐Ÿ‡ธ๐Ÿ‡ฌ","๐Ÿ‡ธ๐Ÿ‡ฝ","๐Ÿ‡ธ๐Ÿ‡ฐ","๐Ÿ‡ธ๐Ÿ‡ฎ","๐Ÿ‡ฌ๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡ง","๐Ÿ‡ธ๐Ÿ‡ด","๐Ÿ‡ฟ๐Ÿ‡ฆ","๐Ÿ‡ฐ๐Ÿ‡ท","๐Ÿ‡ธ๐Ÿ‡ธ","๐Ÿ‡ช๐Ÿ‡ธ","๐Ÿ‡ฑ๐Ÿ‡ฐ","๐Ÿ‡ง๐Ÿ‡ฑ","๐Ÿ‡ธ๐Ÿ‡ญ","๐Ÿ‡ฐ๐Ÿ‡ณ","๐Ÿ‡ฑ๐Ÿ‡จ","๐Ÿ‡ต๐Ÿ‡ฒ","๐Ÿ‡ป๐Ÿ‡จ","๐Ÿ‡ธ๐Ÿ‡ฉ","๐Ÿ‡ธ๐Ÿ‡ท","๐Ÿ‡ธ๐Ÿ‡ช","๐Ÿ‡จ๐Ÿ‡ญ","๐Ÿ‡ธ๐Ÿ‡พ","๐Ÿ‡น๐Ÿ‡ผ","๐Ÿ‡น๐Ÿ‡ฏ","๐Ÿ‡น๐Ÿ‡ฟ","๐Ÿ‡น๐Ÿ‡ญ","๐Ÿ‡น๐Ÿ‡ฑ","๐Ÿ‡น๐Ÿ‡ฌ","๐Ÿ‡น๐Ÿ‡ฐ","๐Ÿ‡น๐Ÿ‡ด","๐Ÿ‡น๐Ÿ‡น","๐Ÿ‡น๐Ÿ‡ณ","๐Ÿ‡น๐Ÿ‡ท","๐Ÿ‡น๐Ÿ‡ฒ","๐Ÿ‡น๐Ÿ‡จ","๐Ÿ‡น๐Ÿ‡ป","๐Ÿ‡บ๐Ÿ‡ฌ","๐Ÿ‡บ๐Ÿ‡ฆ","๐Ÿ‡ฆ๐Ÿ‡ช","๐Ÿ‡ฌ๐Ÿ‡ง","๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ","๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ","๐Ÿด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ","๐Ÿ‡บ๐Ÿ‡ธ","๐Ÿ‡บ๐Ÿ‡พ","๐Ÿ‡ป๐Ÿ‡ฎ","๐Ÿ‡บ๐Ÿ‡ฟ","๐Ÿ‡ป๐Ÿ‡บ","๐Ÿ‡ป๐Ÿ‡ฆ","๐Ÿ‡ป๐Ÿ‡ช","๐Ÿ‡ป๐Ÿ‡ณ","๐Ÿ‡ผ๐Ÿ‡ซ","๐Ÿ‡ช๐Ÿ‡ญ","๐Ÿ‡พ๐Ÿ‡ช","๐Ÿ‡ฟ๐Ÿ‡ฒ","๐Ÿ‡ฟ๐Ÿ‡ผ" + + + + +========================================= + +"๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿฅน","๐Ÿ˜…","๐Ÿ˜‚","๐Ÿคฃ","๐Ÿฅฒ","โ˜บ๏ธ","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿ™‚","๐Ÿ™ƒ","๐Ÿ˜‰","๐Ÿ˜Œ","๐Ÿ˜","๐Ÿฅฐ","๐Ÿ˜˜","๐Ÿ˜—","๐Ÿ˜™","๐Ÿ˜š","๐Ÿ˜‹","๐Ÿ˜›","๐Ÿ˜","๐Ÿ˜œ","๐Ÿคช","๐Ÿคจ","๐Ÿง","๐Ÿค“","๐Ÿ˜Ž","๐Ÿฅธ","๐Ÿคฉ","๐Ÿฅณ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ˜ž","๐Ÿ˜”","๐Ÿ˜Ÿ","๐Ÿ˜•","๐Ÿ™","โ˜น๏ธ","๐Ÿ˜ฃ","๐Ÿ˜–","๐Ÿ˜ซ","๐Ÿ˜ฉ","๐Ÿฅบ","๐Ÿ˜ข","๐Ÿ˜ญ","๐Ÿ˜ค","๐Ÿ˜ ","๐Ÿ˜ก","๐Ÿคฌ","๐Ÿคฏ","๐Ÿ˜ณ","๐Ÿฅต","๐Ÿฅถ","๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿ˜ฑ","๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜“","๐Ÿค—","๐Ÿค”","๐Ÿซฃ","๐Ÿคญ","๐Ÿซข","๐Ÿซก","๐Ÿคซ","๐Ÿซ ","๐Ÿคฅ","๐Ÿ˜ถ","๐Ÿซฅ","๐Ÿ˜","๐Ÿซค","๐Ÿ˜‘","๐Ÿ˜ฌ","๐Ÿ™„","๐Ÿ˜ฏ","๐Ÿ˜ฆ","๐Ÿ˜ง","๐Ÿ˜ฎ","๐Ÿ˜ฒ","๐Ÿฅฑ","๐Ÿ˜ด","๐Ÿคค","๐Ÿ˜ช","๐Ÿ˜ฎโ€๐Ÿ’จ","๐Ÿ˜ต","๐Ÿ˜ตโ€๐Ÿ’ซ","๐Ÿค","๐Ÿฅด","๐Ÿคข","๐Ÿคฎ","๐Ÿคง","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿค‘","๐Ÿค ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ‘น","๐Ÿ‘บ","๐Ÿคก","๐Ÿ’ฉ","๐Ÿ‘ป","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ‘ฝ","๐Ÿ‘พ","๐Ÿค–","๐ŸŽƒ","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น","๐Ÿ˜ป","๐Ÿ˜ผ","๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ", +"๐Ÿซถ", +"๐Ÿคฒ", +"๐Ÿ‘", +"๐Ÿ™Œ", +"๐Ÿ‘", +"๐Ÿค", +"๐Ÿ‘", +"๐Ÿ‘Ž", +"๐Ÿ‘Š", +"โœŠ", +"๐Ÿค›", +"๐Ÿคœ", +"๐Ÿคž", +"โœŒ๏ธ", +"๐Ÿซฐ", +"๐ŸคŸ", +"๐Ÿค˜", +"๐Ÿ‘Œ", +"๐ŸคŒ", +"๐Ÿค", +"๐Ÿซณ", +"๐Ÿซด", +"๐Ÿ‘ˆ", +"๐Ÿ‘‰", +"๐Ÿ‘†", +"๐Ÿ‘‡", +"โ˜๏ธ", +"โœ‹", +"๐Ÿคš", +"๐Ÿ–", +"๐Ÿ––", +"๐Ÿ‘‹", +"๐Ÿค™", +"๐Ÿซฒ", +"๐Ÿซฑ", +"๐Ÿ’ช", +"๐Ÿฆพ", +"๐Ÿ–•", +"โœ๏ธ", +"๐Ÿ™", +"๐Ÿซต", +"๐Ÿฆถ", +"๐Ÿฆต", +"๐Ÿฆฟ","๐Ÿ’„","๐Ÿ’‹","๐Ÿ‘„","๐Ÿซฆ","๐Ÿฆท","๐Ÿ‘…", +"๐Ÿ‘‚", +"๐Ÿฆป", +"๐Ÿ‘ƒ", +"๐Ÿ‘ฃ","๐Ÿ‘","๐Ÿ‘€","๐Ÿซ€","๐Ÿซ","๐Ÿง ","๐Ÿ—ฃ","๐Ÿ‘ค","๐Ÿ‘ฅ","๐Ÿซ‚", +"๐Ÿ‘ถ", +"๐Ÿ‘ง", +"๐Ÿง’", +"๐Ÿ‘ฆ", +"๐Ÿ‘ฉ", +"๐Ÿง‘", +"๐Ÿ‘จ", +"๐Ÿ‘ฉโ€๐Ÿฆฑ", +"๐Ÿง‘โ€๐Ÿฆฑ", +"๐Ÿ‘จโ€๐Ÿฆฑ", +"๐Ÿ‘ฉโ€๐Ÿฆฐ", +"๐Ÿง‘โ€๐Ÿฆฐ", +"๐Ÿ‘จโ€๐Ÿฆฐ", +"๐Ÿ‘ฑโ€โ™€๏ธ", +"๐Ÿ‘ฑ", +"๐Ÿ‘ฑโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€๐Ÿฆณ", +"๐Ÿง‘โ€๐Ÿฆณ", +"๐Ÿ‘จโ€๐Ÿฆณ", +"๐Ÿ‘ฉโ€๐Ÿฆฒ", +"๐Ÿง‘โ€๐Ÿฆฒ", +"๐Ÿ‘จโ€๐Ÿฆฒ", +"๐Ÿง”โ€โ™€๏ธ", +"๐Ÿง”", +"๐Ÿง”โ€โ™‚๏ธ", +"๐Ÿ‘ต", +"๐Ÿง“", +"๐Ÿ‘ด", +"๐Ÿ‘ฒ", +"๐Ÿ‘ณโ€โ™€๏ธ", +"๐Ÿ‘ณ", +"๐Ÿ‘ณโ€โ™‚๏ธ", +"๐Ÿง•", +"๐Ÿ‘ฎโ€โ™€๏ธ", +"๐Ÿ‘ฎ", +"๐Ÿ‘ฎโ€โ™‚๏ธ", +"๐Ÿ‘ทโ€โ™€๏ธ", +"๐Ÿ‘ท", +"๐Ÿ‘ทโ€โ™‚๏ธ", +"๐Ÿ’‚โ€โ™€๏ธ", +"๐Ÿ’‚", +"๐Ÿ’‚โ€โ™‚๏ธ", +"๐Ÿ•ต๏ธโ€โ™€๏ธ", +"๐Ÿ•ต๏ธ", +"๐Ÿ•ต๏ธโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€โš•๏ธ", +"๐Ÿง‘โ€โš•๏ธ", +"๐Ÿ‘จโ€โš•๏ธ", +"๐Ÿ‘ฉโ€๐ŸŒพ", +"๐Ÿง‘โ€๐ŸŒพ", +"๐Ÿ‘จโ€๐ŸŒพ", +"๐Ÿ‘ฉโ€๐Ÿณ", +"๐Ÿง‘โ€๐Ÿณ", +"๐Ÿ‘จโ€๐Ÿณ", +"๐Ÿ‘ฉโ€๐ŸŽ“", +"๐Ÿง‘โ€๐ŸŽ“", +"๐Ÿ‘จโ€๐ŸŽ“", +"๐Ÿ‘ฉโ€๐ŸŽค", +"๐Ÿง‘โ€๐ŸŽค", +"๐Ÿ‘จโ€๐ŸŽค", +"๐Ÿ‘ฉโ€๐Ÿซ", +"๐Ÿง‘โ€๐Ÿซ", +"๐Ÿ‘จโ€๐Ÿซ", +"๐Ÿ‘ฉโ€๐Ÿญ", +"๐Ÿง‘โ€๐Ÿญ", +"๐Ÿ‘จโ€๐Ÿญ", +"๐Ÿ‘ฉโ€๐Ÿ’ป", +"๐Ÿง‘โ€๐Ÿ’ป", +"๐Ÿ‘จโ€๐Ÿ’ป", +"๐Ÿ‘ฉโ€๐Ÿ’ผ", +"๐Ÿง‘โ€๐Ÿ’ผ", +"๐Ÿ‘จโ€๐Ÿ’ผ", +"๐Ÿ‘ฉโ€๐Ÿ”ง", +"๐Ÿง‘โ€๐Ÿ”ง", +"๐Ÿ‘จโ€๐Ÿ”ง", +"๐Ÿ‘ฉโ€๐Ÿ”ฌ", +"๐Ÿง‘โ€๐Ÿ”ฌ", +"๐Ÿ‘จโ€๐Ÿ”ฌ", +"๐Ÿ‘ฉโ€๐ŸŽจ", +"๐Ÿง‘โ€๐ŸŽจ", +"๐Ÿ‘จโ€๐ŸŽจ", +"๐Ÿ‘ฉโ€๐Ÿš’", +"๐Ÿง‘โ€๐Ÿš’", +"๐Ÿ‘จโ€๐Ÿš’", +"๐Ÿ‘ฉโ€โœˆ๏ธ", +"๐Ÿง‘โ€โœˆ๏ธ", +"๐Ÿ‘จโ€โœˆ๏ธ", +"๐Ÿ‘ฉโ€๐Ÿš€", +"๐Ÿง‘โ€๐Ÿš€", +"๐Ÿ‘จโ€๐Ÿš€", +"๐Ÿ‘ฉโ€โš–๏ธ", +"๐Ÿง‘โ€โš–๏ธ", +"๐Ÿ‘จโ€โš–๏ธ", +"๐Ÿ‘ฐโ€โ™€๏ธ", +"๐Ÿ‘ฐ", +"๐Ÿ‘ฐโ€โ™‚๏ธ", +"๐Ÿคตโ€โ™€๏ธ", +"๐Ÿคต", +"๐Ÿคตโ€โ™‚๏ธ", +"๐Ÿ‘ธ", +"๐Ÿซ…", +"๐Ÿคด", +"๐Ÿฅท", +"๐Ÿฆธโ€โ™€๏ธ", +"๐Ÿฆธ", +"๐Ÿฆธโ€โ™‚๏ธ", +"๐Ÿฆนโ€โ™€๏ธ", +"๐Ÿฆน", +"๐Ÿฆนโ€โ™‚๏ธ", +"๐Ÿคถ", +"๐Ÿง‘โ€๐ŸŽ„", +"๐ŸŽ…", +"๐Ÿง™โ€โ™€๏ธ", +"๐Ÿง™", +"๐Ÿง™โ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ", +"๐Ÿง", +"๐Ÿงโ€โ™‚๏ธ", +"๐ŸงŒ", +"๐Ÿง›โ€โ™€๏ธ", +"๐Ÿง›", +"๐Ÿง›โ€โ™‚๏ธ", +"๐ŸงŸโ€โ™€๏ธ","๐ŸงŸ","๐ŸงŸโ€โ™‚๏ธ","๐Ÿงžโ€โ™€๏ธ","๐Ÿงž","๐Ÿงžโ€โ™‚๏ธ", +"๐Ÿงœโ€โ™€๏ธ", +"๐Ÿงœ", +"๐Ÿงœโ€โ™‚๏ธ", +"๐Ÿงšโ€โ™€๏ธ", +"๐Ÿงš", +"๐Ÿงšโ€โ™‚๏ธ", +"๐Ÿ‘ผ", +"๐Ÿคฐ", +"๐Ÿซ„", +"๐Ÿซƒ", +"๐Ÿคฑ", +"๐Ÿ‘ฉโ€๐Ÿผ", +"๐Ÿง‘โ€๐Ÿผ", +"๐Ÿ‘จโ€๐Ÿผ", +"๐Ÿ™‡โ€โ™€๏ธ", +"๐Ÿ™‡", +"๐Ÿ™‡โ€โ™‚๏ธ", +"๐Ÿ’โ€โ™€๏ธ", +"๐Ÿ’", +"๐Ÿ’โ€โ™‚๏ธ", +"๐Ÿ™…โ€โ™€๏ธ", +"๐Ÿ™…", +"๐Ÿ™…โ€โ™‚๏ธ", +"๐Ÿ™†โ€โ™€๏ธ", +"๐Ÿ™†", +"๐Ÿ™†โ€โ™‚๏ธ", +"๐Ÿ™‹โ€โ™€๏ธ", +"๐Ÿ™‹", +"๐Ÿ™‹โ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ", +"๐Ÿง", +"๐Ÿงโ€โ™‚๏ธ", +"๐Ÿคฆโ€โ™€๏ธ", +"๐Ÿคฆ", +"๐Ÿคฆโ€โ™‚๏ธ", +"๐Ÿคทโ€โ™€๏ธ", +"๐Ÿคท", +"๐Ÿคทโ€โ™‚๏ธ", +"๐Ÿ™Žโ€โ™€๏ธ", +"๐Ÿ™Ž", +"๐Ÿ™Žโ€โ™‚๏ธ", +"๐Ÿ™โ€โ™€๏ธ", +"๐Ÿ™", +"๐Ÿ™โ€โ™‚๏ธ", +"๐Ÿ’‡โ€โ™€๏ธ", +"๐Ÿ’‡", +"๐Ÿ’‡โ€โ™‚๏ธ", +"๐Ÿ’†โ€โ™€๏ธ", +"๐Ÿ’†", +"๐Ÿ’†โ€โ™‚๏ธ", +"๐Ÿง–โ€โ™€๏ธ", +"๐Ÿง–", +"๐Ÿง–โ€โ™‚๏ธ", +"๐Ÿ’…", +"๐Ÿคณ", +"๐Ÿ’ƒ", +"๐Ÿ•บ", +"๐Ÿ‘ฏโ€โ™€๏ธ","๐Ÿ‘ฏ","๐Ÿ‘ฏโ€โ™‚๏ธ", +"๐Ÿ•ด", +"๐Ÿ‘ฉโ€๐Ÿฆฝ", +"๐Ÿง‘โ€๐Ÿฆฝ", +"๐Ÿ‘จโ€๐Ÿฆฝ", +"๐Ÿ‘ฉโ€๐Ÿฆผ", +"๐Ÿง‘โ€๐Ÿฆผ", +"๐Ÿ‘จโ€๐Ÿฆผ", +"๐Ÿšถโ€โ™€๏ธ", +"๐Ÿšถ", +"๐Ÿšถโ€โ™‚๏ธ", +"๐Ÿ‘ฉโ€๐Ÿฆฏ", +"๐Ÿง‘โ€๐Ÿฆฏ", +"๐Ÿ‘จโ€๐Ÿฆฏ", +"๐ŸงŽโ€โ™€๏ธ", +"๐ŸงŽ", +"๐ŸงŽโ€โ™‚๏ธ", +"๐Ÿƒโ€โ™€๏ธ", +"๐Ÿƒ", +"๐Ÿƒโ€โ™‚๏ธ", +"๐Ÿงโ€โ™€๏ธ", +"๐Ÿง", +"๐Ÿงโ€โ™‚๏ธ", +"๐Ÿ‘ซ", +"๐Ÿ‘ญ", +"๐Ÿ‘ฌ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ", +"๐Ÿ’‘", +"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", +"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ", +"๐Ÿ’", +"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", +"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ง","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ง","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","๐Ÿชข","๐Ÿงถ","๐Ÿงต","๐Ÿชก","๐Ÿงฅ","๐Ÿฅผ","๐Ÿฆบ","๐Ÿ‘š","๐Ÿ‘•","๐Ÿ‘–","๐Ÿฉฒ","๐Ÿฉณ","๐Ÿ‘”","๐Ÿ‘—","๐Ÿ‘™","๐Ÿฉฑ","๐Ÿ‘˜","๐Ÿฅป","๐Ÿฉด","๐Ÿฅฟ","๐Ÿ‘ ","๐Ÿ‘ก","๐Ÿ‘ข","๐Ÿ‘ž","๐Ÿ‘Ÿ","๐Ÿฅพ","๐Ÿงฆ","๐Ÿงค","๐Ÿงฃ","๐ŸŽฉ","๐Ÿงข","๐Ÿ‘’","๐ŸŽ“","โ›‘","๐Ÿช–","๐Ÿ‘‘","๐Ÿ’","๐Ÿ‘","๐Ÿ‘›","๐Ÿ‘œ","๐Ÿ’ผ","๐ŸŽ’","๐Ÿงณ","๐Ÿ‘“","๐Ÿ•ถ","๐Ÿฅฝ","๐ŸŒ‚" + + +"โšฝ๏ธ","๐Ÿ€","๐Ÿˆ","โšพ๏ธ","๐ŸฅŽ","๐ŸŽพ","๐Ÿ","๐Ÿ‰","๐Ÿฅ","๐ŸŽฑ","๐Ÿช€","๐Ÿ“","๐Ÿธ","๐Ÿ’","๐Ÿ‘","๐Ÿฅ","๐Ÿ","๐Ÿชƒ","๐Ÿฅ…","โ›ณ๏ธ","๐Ÿช","๐Ÿน","๐ŸŽฃ","๐Ÿคฟ","๐ŸฅŠ","๐Ÿฅ‹","๐ŸŽฝ","๐Ÿ›น","๐Ÿ›ผ","๐Ÿ›ท","โ›ธ","๐ŸฅŒ","๐ŸŽฟ","โ›ท","๐Ÿ‚","๐Ÿช‚", +"๐Ÿ‹๏ธโ€โ™€๏ธ", +"๐Ÿ‹๏ธ", +"๐Ÿ‹๏ธโ€โ™‚๏ธ", +"๐Ÿคผโ€โ™€๏ธ","๐Ÿคผ","๐Ÿคผโ€โ™‚๏ธ", +"๐Ÿคธโ€โ™€๏ธ", +"๐Ÿคธ", +"๐Ÿคธโ€โ™‚๏ธ", +"โ›น๏ธโ€โ™€๏ธ", +"โ›น๏ธ", +"โ›น๏ธโ€โ™‚๏ธ", +"๐Ÿคบ", +"๐Ÿคพโ€โ™€๏ธ", +"๐Ÿคพ", +"๐Ÿคพโ€โ™‚๏ธ", +"๐ŸŒ๏ธโ€โ™€๏ธ", +"๐ŸŒ๏ธ", +"๐ŸŒ๏ธโ€โ™‚๏ธ", +"๐Ÿ‡", +"๐Ÿง˜โ€โ™€๏ธ", +"๐Ÿง˜", +"๐Ÿง˜โ€โ™‚๏ธ", +"๐Ÿ„โ€โ™€๏ธ", +"๐Ÿ„", +"๐Ÿ„โ€โ™‚๏ธ", +"๐ŸŠโ€โ™€๏ธ", +"๐ŸŠ", +"๐ŸŠโ€โ™‚๏ธ", +"๐Ÿคฝโ€โ™€๏ธ", +"๐Ÿคฝ", +"๐Ÿคฝโ€โ™‚๏ธ", +"๐Ÿšฃโ€โ™€๏ธ", +"๐Ÿšฃ", +"๐Ÿšฃโ€โ™‚๏ธ", +"๐Ÿง—โ€โ™€๏ธ", +"๐Ÿง—", +"๐Ÿง—โ€โ™‚๏ธ", +"๐Ÿšตโ€โ™€๏ธ", +"๐Ÿšต", +"๐Ÿšตโ€โ™‚๏ธ", +"๐Ÿšดโ€โ™€๏ธ", +"๐Ÿšด", +"๐Ÿšดโ€โ™‚๏ธ", +"๐Ÿ†","๐Ÿฅ‡","๐Ÿฅˆ","๐Ÿฅ‰","๐Ÿ…","๐ŸŽ–","๐Ÿต","๐ŸŽ—","๐ŸŽซ","๐ŸŽŸ","๐ŸŽช", +"๐Ÿคนโ€โ™€๏ธ", +"๐Ÿคน", +"๐Ÿคนโ€โ™‚๏ธ", +"๐ŸŽญ","๐Ÿฉฐ","๐ŸŽจ","๐ŸŽฌ","๐ŸŽค","๐ŸŽง","๐ŸŽผ","๐ŸŽน","๐Ÿฅ","๐Ÿช˜","๐ŸŽท","๐ŸŽบ","๐Ÿช—","๐ŸŽธ","๐Ÿช•","๐ŸŽป","๐ŸŽฒ","โ™Ÿ","๐ŸŽฏ","๐ŸŽณ","๐ŸŽฎ","๐ŸŽฐ","๐Ÿงฉ" + + + + +"โŒš๏ธ","๐Ÿ“ฑ","๐Ÿ“ฒ","๐Ÿ’ป","โŒจ๏ธ","๐Ÿ–ฅ","๐Ÿ–จ","๐Ÿ–ฑ","๐Ÿ–ฒ","๐Ÿ•น","๐Ÿ—œ","๐Ÿ’ฝ","๐Ÿ’พ","๐Ÿ’ฟ","๐Ÿ“€","๐Ÿ“ผ","๐Ÿ“ท","๐Ÿ“ธ","๐Ÿ“น","๐ŸŽฅ","๐Ÿ“ฝ","๐ŸŽž","๐Ÿ“ž","โ˜Ž๏ธ","๐Ÿ“Ÿ","๐Ÿ“ ","๐Ÿ“บ","๐Ÿ“ป","๐ŸŽ™","๐ŸŽš","๐ŸŽ›","๐Ÿงญ","โฑ","โฒ","โฐ","๐Ÿ•ฐ","โŒ›๏ธ","โณ","๐Ÿ“ก","๐Ÿ”‹","๐Ÿชซ","๐Ÿ”Œ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ•ฏ","๐Ÿช”","๐Ÿงฏ","๐Ÿ›ข","๐Ÿ’ธ","๐Ÿ’ต","๐Ÿ’ด","๐Ÿ’ถ","๐Ÿ’ท","๐Ÿช™","๐Ÿ’ฐ","๐Ÿ’ณ","๐Ÿชช","๐Ÿ’Ž","โš–๏ธ","๐Ÿชœ","๐Ÿงฐ","๐Ÿช›","๐Ÿ”ง","๐Ÿ”จ","โš’","๐Ÿ› ","โ›","๐Ÿชš","๐Ÿ”ฉ","โš™๏ธ","๐Ÿชค","๐Ÿงฑ","โ›“","๐Ÿงฒ","๐Ÿ”ซ","๐Ÿ’ฃ","๐Ÿงจ","๐Ÿช“","๐Ÿ”ช","๐Ÿ—ก","โš”๏ธ","๐Ÿ›ก","๐Ÿšฌ","โšฐ๏ธ","๐Ÿชฆ","โšฑ๏ธ","๐Ÿบ","๐Ÿ”ฎ","๐Ÿ“ฟ","๐Ÿงฟ","๐Ÿชฌ","๐Ÿ’ˆ","โš—๏ธ","๐Ÿ”ญ","๐Ÿ”ฌ","๐Ÿ•ณ","๐Ÿฉป","๐Ÿฉน","๐Ÿฉบ","๐Ÿ’Š","๐Ÿ’‰","๐Ÿฉธ","๐Ÿงฌ","๐Ÿฆ ","๐Ÿงซ","๐Ÿงช","๐ŸŒก","๐Ÿงน","๐Ÿช ","๐Ÿงบ","๐Ÿงป","๐Ÿšฝ","๐Ÿšฐ","๐Ÿšฟ","๐Ÿ›", +"๐Ÿ›€", +"๐Ÿงผ","๐Ÿชฅ","๐Ÿช’","๐Ÿงฝ","๐Ÿชฃ","๐Ÿงด","๐Ÿ›Ž","๐Ÿ”‘","๐Ÿ—","๐Ÿšช","๐Ÿช‘","๐Ÿ›‹","๐Ÿ›","๐Ÿ›Œ","๐Ÿงธ","๐Ÿช†","๐Ÿ–ผ","๐Ÿชž","๐ŸชŸ","๐Ÿ›","๐Ÿ›’","๐ŸŽ","๐ŸŽˆ","๐ŸŽ","๐ŸŽ€","๐Ÿช„","๐Ÿช…","๐ŸŽŠ","๐ŸŽ‰","๐ŸŽŽ","๐Ÿฎ","๐ŸŽ","๐Ÿชฉ","๐Ÿงง","โœ‰๏ธ","๐Ÿ“ฉ","๐Ÿ“จ","๐Ÿ“ง","๐Ÿ’Œ","๐Ÿ“ฅ","๐Ÿ“ค","๐Ÿ“ฆ","๐Ÿท","๐Ÿชง","๐Ÿ“ช","๐Ÿ“ซ","๐Ÿ“ฌ","๐Ÿ“ญ","๐Ÿ“ฎ","๐Ÿ“ฏ","๐Ÿ“œ","๐Ÿ“ƒ","๐Ÿ“„","๐Ÿ“‘","๐Ÿงพ","๐Ÿ“Š","๐Ÿ“ˆ","๐Ÿ“‰","๐Ÿ—’","๐Ÿ—“","๐Ÿ“†","๐Ÿ“…","๐Ÿ—‘","๐Ÿ“‡","๐Ÿ—ƒ","๐Ÿ—ณ","๐Ÿ—„","๐Ÿ“‹","๐Ÿ“","๐Ÿ“‚","๐Ÿ—‚","๐Ÿ—ž","๐Ÿ“ฐ","๐Ÿ““","๐Ÿ“”","๐Ÿ“’","๐Ÿ“•","๐Ÿ“—","๐Ÿ“˜","๐Ÿ“™","๐Ÿ“š","๐Ÿ“–","๐Ÿ”–","๐Ÿงท","๐Ÿ”—","๐Ÿ“Ž","๐Ÿ–‡","๐Ÿ“","๐Ÿ“","๐Ÿงฎ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ–Š","๐Ÿ–‹","โœ’๏ธ","๐Ÿ–Œ","๐Ÿ–","๐Ÿ“","โœ๏ธ","๐Ÿ”","๐Ÿ”Ž","๐Ÿ”","๐Ÿ”","๐Ÿ”’","๐Ÿ”“" + + + +========================================= +"๐Ÿซถ","๐Ÿคฒ","๐Ÿ‘","๐Ÿ™Œ","๐Ÿ‘","๐Ÿ‘","๐Ÿ‘Ž","๐Ÿ‘Š","โœŠ","๐Ÿค›","๐Ÿคœ","๐Ÿคž","โœŒ๏ธ","๐Ÿซฐ","๐ŸคŸ","๐Ÿค˜","๐Ÿ‘Œ","๐ŸคŒ","๐Ÿค","๐Ÿซณ","๐Ÿซด","๐Ÿ‘ˆ","๐Ÿ‘‰","๐Ÿ‘†","๐Ÿ‘‡","โ˜๏ธ","โœ‹","๐Ÿคš","๐Ÿ–","๐Ÿ––","๐Ÿ‘‹","๐Ÿค™","๐Ÿซฒ","๐Ÿซฑ","๐Ÿ’ช","๐Ÿ–•","โœ๏ธ","๐Ÿ™","๐Ÿซต","๐Ÿฆถ","๐Ÿฆต","๐Ÿ‘‚","๐Ÿฆป","๐Ÿ‘ƒ","๐Ÿ‘ถ","๐Ÿ‘ง","๐Ÿง’","๐Ÿ‘ฆ","๐Ÿ‘ฉ","๐Ÿง‘","๐Ÿ‘จ","๐Ÿ‘ฉโ€๐Ÿฆฑ","๐Ÿง‘โ€๐Ÿฆฑ","๐Ÿ‘จโ€๐Ÿฆฑ","๐Ÿ‘ฉโ€๐Ÿฆฐ","๐Ÿง‘โ€๐Ÿฆฐ","๐Ÿ‘จโ€๐Ÿฆฐ","๐Ÿ‘ฑโ€โ™€๏ธ","๐Ÿ‘ฑ","๐Ÿ‘ฑโ€โ™‚๏ธ","๐Ÿ‘ฉโ€๐Ÿฆณ","๐Ÿง‘โ€๐Ÿฆณ","๐Ÿ‘จโ€๐Ÿฆณ","๐Ÿ‘ฉโ€๐Ÿฆฒ","๐Ÿง‘โ€๐Ÿฆฒ","๐Ÿ‘จโ€๐Ÿฆฒ","๐Ÿง”โ€โ™€๏ธ","๐Ÿง”","๐Ÿง”โ€โ™‚๏ธ","๐Ÿ‘ต","๐Ÿง“","๐Ÿ‘ด","๐Ÿ‘ฒ","๐Ÿ‘ณโ€โ™€๏ธ","๐Ÿ‘ณ","๐Ÿ‘ณโ€โ™‚๏ธ","๐Ÿง•","๐Ÿ‘ฎโ€โ™€๏ธ","๐Ÿ‘ฎ","๐Ÿ‘ฎโ€โ™‚๏ธ","๐Ÿ‘ทโ€โ™€๏ธ","๐Ÿ‘ท","๐Ÿ‘ทโ€โ™‚๏ธ","๐Ÿ’‚โ€โ™€๏ธ","๐Ÿ’‚","๐Ÿ’‚โ€โ™‚๏ธ","๐Ÿ•ต๏ธโ€โ™€๏ธ","๐Ÿ•ต๏ธ","๐Ÿ•ต๏ธโ€โ™‚๏ธ","๐Ÿ‘ฉโ€โš•๏ธ","๐Ÿง‘โ€โš•๏ธ","๐Ÿ‘จโ€โš•๏ธ","๐Ÿ‘ฉโ€๐ŸŒพ","๐Ÿง‘โ€๐ŸŒพ","๐Ÿ‘จโ€๐ŸŒพ","๐Ÿ‘ฉโ€๐Ÿณ","๐Ÿง‘โ€๐Ÿณ","๐Ÿ‘จโ€๐Ÿณ","๐Ÿ‘ฉโ€๐ŸŽ“","๐Ÿง‘โ€๐ŸŽ“","๐Ÿ‘จโ€๐ŸŽ“","๐Ÿ‘ฉโ€๐ŸŽค","๐Ÿง‘โ€๐ŸŽค","๐Ÿ‘จโ€๐ŸŽค","๐Ÿ‘ฉโ€๐Ÿซ","๐Ÿง‘โ€๐Ÿซ","๐Ÿ‘จโ€๐Ÿซ","๐Ÿ‘ฉโ€๐Ÿญ","๐Ÿง‘โ€๐Ÿญ","๐Ÿ‘จโ€๐Ÿญ","๐Ÿ‘ฉโ€๐Ÿ’ป","๐Ÿง‘โ€๐Ÿ’ป","๐Ÿ‘จโ€๐Ÿ’ป","๐Ÿ‘ฉโ€๐Ÿ’ผ","๐Ÿง‘โ€๐Ÿ’ผ","๐Ÿ‘จโ€๐Ÿ’ผ","๐Ÿ‘ฉโ€๐Ÿ”ง","๐Ÿง‘โ€๐Ÿ”ง","๐Ÿ‘จโ€๐Ÿ”ง","๐Ÿ‘ฉโ€๐Ÿ”ฌ","๐Ÿง‘โ€๐Ÿ”ฌ","๐Ÿ‘จโ€๐Ÿ”ฌ","๐Ÿ‘ฉโ€๐ŸŽจ","๐Ÿง‘โ€๐ŸŽจ","๐Ÿ‘จโ€๐ŸŽจ","๐Ÿ‘ฉโ€๐Ÿš’","๐Ÿง‘โ€๐Ÿš’","๐Ÿ‘จโ€๐Ÿš’","๐Ÿ‘ฉโ€โœˆ๏ธ","๐Ÿง‘โ€โœˆ๏ธ","๐Ÿ‘จโ€โœˆ๏ธ","๐Ÿ‘ฉโ€๐Ÿš€","๐Ÿง‘โ€๐Ÿš€","๐Ÿ‘จโ€๐Ÿš€","๐Ÿ‘ฉโ€โš–๏ธ","๐Ÿง‘โ€โš–๏ธ","๐Ÿ‘จโ€โš–๏ธ","๐Ÿ‘ฐโ€โ™€๏ธ","๐Ÿ‘ฐ","๐Ÿ‘ฐโ€โ™‚๏ธ","๐Ÿคตโ€โ™€๏ธ","๐Ÿคต","๐Ÿคตโ€โ™‚๏ธ","๐Ÿ‘ธ","๐Ÿซ…","๐Ÿคด","๐Ÿฅท","๐Ÿฆธโ€โ™€๏ธ","๐Ÿฆธ","๐Ÿฆธโ€โ™‚๏ธ","๐Ÿฆนโ€โ™€๏ธ","๐Ÿฆน","๐Ÿฆนโ€โ™‚๏ธ","๐Ÿคถ","๐Ÿง‘โ€๐ŸŽ„","๐ŸŽ…","๐Ÿง™โ€โ™€๏ธ","๐Ÿง™","๐Ÿง™โ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿง›โ€โ™€๏ธ","๐Ÿง›","๐Ÿง›โ€โ™‚๏ธ","๐Ÿงœโ€โ™€๏ธ","๐Ÿงœ","๐Ÿงœโ€โ™‚๏ธ","๐Ÿงšโ€โ™€๏ธ","๐Ÿงš","๐Ÿงšโ€โ™‚๏ธ","๐Ÿ‘ผ","๐Ÿคฐ","๐Ÿซ„","๐Ÿซƒ","๐Ÿคฑ","๐Ÿ‘ฉโ€๐Ÿผ","๐Ÿง‘โ€๐Ÿผ","๐Ÿ‘จโ€๐Ÿผ","๐Ÿ™‡โ€โ™€๏ธ","๐Ÿ™‡","๐Ÿ™‡โ€โ™‚๏ธ","๐Ÿ’โ€โ™€๏ธ","๐Ÿ’","๐Ÿ’โ€โ™‚๏ธ","๐Ÿ™…โ€โ™€๏ธ","๐Ÿ™…","๐Ÿ™…โ€โ™‚๏ธ","๐Ÿ™†โ€โ™€๏ธ","๐Ÿ™†","๐Ÿ™†โ€โ™‚๏ธ","๐Ÿ™‹โ€โ™€๏ธ","๐Ÿ™‹","๐Ÿ™‹โ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿคฆโ€โ™€๏ธ","๐Ÿคฆ","๐Ÿคฆโ€โ™‚๏ธ","๐Ÿคทโ€โ™€๏ธ","๐Ÿคท","๐Ÿคทโ€โ™‚๏ธ","๐Ÿ™Žโ€โ™€๏ธ","๐Ÿ™Ž","๐Ÿ™Žโ€โ™‚๏ธ","๐Ÿ™โ€โ™€๏ธ","๐Ÿ™","๐Ÿ™โ€โ™‚๏ธ","๐Ÿ’‡โ€โ™€๏ธ","๐Ÿ’‡","๐Ÿ’‡โ€โ™‚๏ธ","๐Ÿ’†โ€โ™€๏ธ","๐Ÿ’†","๐Ÿ’†โ€โ™‚๏ธ","๐Ÿง–โ€โ™€๏ธ","๐Ÿง–","๐Ÿง–โ€โ™‚๏ธ","๐Ÿ’…","๐Ÿคณ","๐Ÿ’ƒ","๐Ÿ•บ","๐Ÿ•ด","๐Ÿ‘ฉโ€๐Ÿฆฝ","๐Ÿง‘โ€๐Ÿฆฝ","๐Ÿ‘จโ€๐Ÿฆฝ","๐Ÿ‘ฉโ€๐Ÿฆผ","๐Ÿง‘โ€๐Ÿฆผ","๐Ÿ‘จโ€๐Ÿฆผ","๐Ÿšถโ€โ™€๏ธ","๐Ÿšถ","๐Ÿšถโ€โ™‚๏ธ","๐Ÿ‘ฉโ€๐Ÿฆฏ","๐Ÿง‘โ€๐Ÿฆฏ","๐Ÿ‘จโ€๐Ÿฆฏ","๐ŸงŽโ€โ™€๏ธ","๐ŸงŽ","๐ŸงŽโ€โ™‚๏ธ","๐Ÿƒโ€โ™€๏ธ","๐Ÿƒ","๐Ÿƒโ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿ‹๏ธโ€โ™€๏ธ","๐Ÿ‹๏ธ","๐Ÿ‹๏ธโ€โ™‚๏ธ","๐Ÿคธโ€โ™€๏ธ","๐Ÿคธ","๐Ÿคธโ€โ™‚๏ธ","โ›น๏ธโ€โ™€๏ธ","โ›น๏ธ","โ›น๏ธโ€โ™‚๏ธ","๐Ÿคพโ€โ™€๏ธ","๐Ÿคพ","๐Ÿคพโ€โ™‚๏ธ","๐ŸŒ๏ธโ€โ™€๏ธ","๐ŸŒ๏ธ","๐ŸŒ๏ธโ€โ™‚๏ธ","๐Ÿ‡","๐Ÿง˜โ€โ™€๏ธ","๐Ÿง˜","๐Ÿง˜โ€โ™‚๏ธ","๐Ÿ„โ€โ™€๏ธ","๐Ÿ„","๐Ÿ„โ€โ™‚๏ธ","๐ŸŠโ€โ™€๏ธ","๐ŸŠ","๐ŸŠโ€โ™‚๏ธ","๐Ÿคฝโ€โ™€๏ธ","๐Ÿคฝ","๐Ÿคฝโ€โ™‚๏ธ","๐Ÿšฃโ€โ™€๏ธ","๐Ÿšฃ","๐Ÿšฃโ€โ™‚๏ธ","๐Ÿง—โ€โ™€๏ธ","๐Ÿง—","๐Ÿง—โ€โ™‚๏ธ","๐Ÿšตโ€โ™€๏ธ","๐Ÿšต","๐Ÿšตโ€โ™‚๏ธ","๐Ÿšดโ€โ™€๏ธ","๐Ÿšด","๐Ÿšดโ€โ™‚๏ธ","๐Ÿคนโ€โ™€๏ธ","๐Ÿคน","๐Ÿคนโ€โ™‚๏ธ","๐Ÿ›€" + + +"๐Ÿค","๐Ÿ‘ซ","๐Ÿ‘ญ","๐Ÿ‘ฌ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ","๐Ÿ’‘","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ","๐Ÿ’","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ" + +========================================= + + +"๐Ÿ—จ", "๐Ÿ‘ช" \ No newline at end of file diff --git a/icons/box_button_back.png b/icons/box_button_back.png index 9db1870..3fcc4ad 100644 Binary files a/icons/box_button_back.png and b/icons/box_button_back.png differ diff --git a/icons/box_button_back@2x.png b/icons/box_button_back@2x.png index b729fc2..12276d3 100644 Binary files a/icons/box_button_back@2x.png and b/icons/box_button_back@2x.png differ diff --git a/icons/box_button_back@3x.png b/icons/box_button_back@3x.png index 5e5cf8b..d946415 100644 Binary files a/icons/box_button_back@3x.png and b/icons/box_button_back@3x.png differ diff --git a/icons/box_button_close.png b/icons/box_button_close.png index 3b04028..aa732af 100644 Binary files a/icons/box_button_close.png and b/icons/box_button_close.png differ diff --git a/icons/box_button_close@2x.png b/icons/box_button_close@2x.png index fea726b..976b284 100644 Binary files a/icons/box_button_close@2x.png and b/icons/box_button_close@2x.png differ diff --git a/icons/box_button_close@3x.png b/icons/box_button_close@3x.png index e818a6a..92e6626 100644 Binary files a/icons/box_button_close@3x.png and b/icons/box_button_close@3x.png differ diff --git a/icons/box_search.png b/icons/box_search.png index 0473526..fff0035 100644 Binary files a/icons/box_search.png and b/icons/box_search.png differ diff --git a/icons/box_search@2x.png b/icons/box_search@2x.png index 4d2c66f..f633fd7 100644 Binary files a/icons/box_search@2x.png and b/icons/box_search@2x.png differ diff --git a/icons/box_search@3x.png b/icons/box_search@3x.png index 3b681f6..5cd6c59 100644 Binary files a/icons/box_search@3x.png and b/icons/box_search@3x.png differ diff --git a/icons/calls/call_shadow_left.png b/icons/calls/call_shadow_left.png index 74864ad..01d48f5 100644 Binary files a/icons/calls/call_shadow_left.png and b/icons/calls/call_shadow_left.png differ diff --git a/icons/calls/call_shadow_left@2x.png b/icons/calls/call_shadow_left@2x.png index 6a0e6e4..40cb398 100644 Binary files a/icons/calls/call_shadow_left@2x.png and b/icons/calls/call_shadow_left@2x.png differ diff --git a/icons/calls/call_shadow_left@3x.png b/icons/calls/call_shadow_left@3x.png index 30257eb..9814ab4 100644 Binary files a/icons/calls/call_shadow_left@3x.png and b/icons/calls/call_shadow_left@3x.png differ diff --git a/icons/calls/call_shadow_top.png b/icons/calls/call_shadow_top.png index 653e0af..8cfcb9c 100644 Binary files a/icons/calls/call_shadow_top.png and b/icons/calls/call_shadow_top.png differ diff --git a/icons/calls/call_shadow_top@2x.png b/icons/calls/call_shadow_top@2x.png index 47c672c..709c6e4 100644 Binary files a/icons/calls/call_shadow_top@2x.png and b/icons/calls/call_shadow_top@2x.png differ diff --git a/icons/calls/call_shadow_top@3x.png b/icons/calls/call_shadow_top@3x.png index 350db04..580760e 100644 Binary files a/icons/calls/call_shadow_top@3x.png and b/icons/calls/call_shadow_top@3x.png differ diff --git a/icons/calls/call_shadow_top_left.png b/icons/calls/call_shadow_top_left.png index baba493..8ad29e9 100644 Binary files a/icons/calls/call_shadow_top_left.png and b/icons/calls/call_shadow_top_left.png differ diff --git a/icons/calls/call_shadow_top_left@2x.png b/icons/calls/call_shadow_top_left@2x.png index 0d9672f..8a8cfd3 100644 Binary files a/icons/calls/call_shadow_top_left@2x.png and b/icons/calls/call_shadow_top_left@2x.png differ diff --git a/icons/calls/call_shadow_top_left@3x.png b/icons/calls/call_shadow_top_left@3x.png index 260bb26..c372e2d 100644 Binary files a/icons/calls/call_shadow_top_left@3x.png and b/icons/calls/call_shadow_top_left@3x.png differ diff --git a/icons/default_checkbox_check.png b/icons/default_checkbox_check.png index 574f571..cee8d45 100644 Binary files a/icons/default_checkbox_check.png and b/icons/default_checkbox_check.png differ diff --git a/icons/default_checkbox_check@2x.png b/icons/default_checkbox_check@2x.png index 6d3859c..9109508 100644 Binary files a/icons/default_checkbox_check@2x.png and b/icons/default_checkbox_check@2x.png differ diff --git a/icons/default_checkbox_check@3x.png b/icons/default_checkbox_check@3x.png index 46f67cb..ebe40ff 100644 Binary files a/icons/default_checkbox_check@3x.png and b/icons/default_checkbox_check@3x.png differ diff --git a/icons/dropdown_submenu_arrow.png b/icons/dropdown_submenu_arrow.png deleted file mode 100644 index d7015e7..0000000 Binary files a/icons/dropdown_submenu_arrow.png and /dev/null differ diff --git a/icons/dropdown_submenu_arrow@2x.png b/icons/dropdown_submenu_arrow@2x.png deleted file mode 100644 index 49ca1c3..0000000 Binary files a/icons/dropdown_submenu_arrow@2x.png and /dev/null differ diff --git a/icons/dropdown_submenu_arrow@3x.png b/icons/dropdown_submenu_arrow@3x.png deleted file mode 100644 index 68130c2..0000000 Binary files a/icons/dropdown_submenu_arrow@3x.png and /dev/null differ diff --git a/icons/simple_close.png b/icons/simple_close.png index 10f8b03..808a461 100644 Binary files a/icons/simple_close.png and b/icons/simple_close.png differ diff --git a/icons/simple_close@2x.png b/icons/simple_close@2x.png index a53c4af..e8386ad 100644 Binary files a/icons/simple_close@2x.png and b/icons/simple_close@2x.png differ diff --git a/icons/simple_close@3x.png b/icons/simple_close@3x.png index 5a5f817..e51bb68 100644 Binary files a/icons/simple_close@3x.png and b/icons/simple_close@3x.png differ diff --git a/icons/title_button_close.png b/icons/title_button_close.png index 7f3b14e..248e5a1 100644 Binary files a/icons/title_button_close.png and b/icons/title_button_close.png differ diff --git a/icons/title_button_close@2x.png b/icons/title_button_close@2x.png index e966135..9bc27c8 100644 Binary files a/icons/title_button_close@2x.png and b/icons/title_button_close@2x.png differ diff --git a/icons/title_button_close@3x.png b/icons/title_button_close@3x.png index 1781b22..789dde7 100644 Binary files a/icons/title_button_close@3x.png and b/icons/title_button_close@3x.png differ diff --git a/icons/title_button_maximize.png b/icons/title_button_maximize.png index 9b0689d..a4e7f74 100644 Binary files a/icons/title_button_maximize.png and b/icons/title_button_maximize.png differ diff --git a/icons/title_button_maximize@2x.png b/icons/title_button_maximize@2x.png index 606e0d7..feca74c 100644 Binary files a/icons/title_button_maximize@2x.png and b/icons/title_button_maximize@2x.png differ diff --git a/icons/title_button_maximize@3x.png b/icons/title_button_maximize@3x.png index bdda763..75e7923 100644 Binary files a/icons/title_button_maximize@3x.png and b/icons/title_button_maximize@3x.png differ diff --git a/icons/title_button_minimize.png b/icons/title_button_minimize.png index ba19ab5..0dda203 100644 Binary files a/icons/title_button_minimize.png and b/icons/title_button_minimize.png differ diff --git a/icons/title_button_minimize@2x.png b/icons/title_button_minimize@2x.png index 4d643aa..be5c172 100644 Binary files a/icons/title_button_minimize@2x.png and b/icons/title_button_minimize@2x.png differ diff --git a/icons/title_button_minimize@3x.png b/icons/title_button_minimize@3x.png index 416c391..57c513f 100644 Binary files a/icons/title_button_minimize@3x.png and b/icons/title_button_minimize@3x.png differ diff --git a/icons/title_button_restore.png b/icons/title_button_restore.png index 0b1912a..91f5c10 100644 Binary files a/icons/title_button_restore.png and b/icons/title_button_restore.png differ diff --git a/icons/title_button_restore@2x.png b/icons/title_button_restore@2x.png index 2c55555..926e793 100644 Binary files a/icons/title_button_restore@2x.png and b/icons/title_button_restore@2x.png differ diff --git a/icons/title_button_restore@3x.png b/icons/title_button_restore@3x.png index b366e5a..b2f3b1a 100644 Binary files a/icons/title_button_restore@3x.png and b/icons/title_button_restore@3x.png differ diff --git a/icons/title_shadow_close.png b/icons/title_shadow_close.png index 84fa43c..6f3783f 100644 Binary files a/icons/title_shadow_close.png and b/icons/title_shadow_close.png differ diff --git a/icons/title_shadow_close@2x.png b/icons/title_shadow_close@2x.png index 4577d49..a801255 100644 Binary files a/icons/title_shadow_close@2x.png and b/icons/title_shadow_close@2x.png differ diff --git a/icons/title_shadow_close@3x.png b/icons/title_shadow_close@3x.png index da9e12f..c0c3b4e 100644 Binary files a/icons/title_shadow_close@3x.png and b/icons/title_shadow_close@3x.png differ diff --git a/icons/title_shadow_maximize.png b/icons/title_shadow_maximize.png index 83ab630..190744f 100644 Binary files a/icons/title_shadow_maximize.png and b/icons/title_shadow_maximize.png differ diff --git a/icons/title_shadow_maximize@2x.png b/icons/title_shadow_maximize@2x.png index 30da5ba..d6ae395 100644 Binary files a/icons/title_shadow_maximize@2x.png and b/icons/title_shadow_maximize@2x.png differ diff --git a/icons/title_shadow_maximize@3x.png b/icons/title_shadow_maximize@3x.png index 809d1b0..0271349 100644 Binary files a/icons/title_shadow_maximize@3x.png and b/icons/title_shadow_maximize@3x.png differ diff --git a/icons/title_shadow_minimize.png b/icons/title_shadow_minimize.png index ad84b49..fad46d1 100644 Binary files a/icons/title_shadow_minimize.png and b/icons/title_shadow_minimize.png differ diff --git a/icons/title_shadow_minimize@2x.png b/icons/title_shadow_minimize@2x.png index 7f22fbc..683b705 100644 Binary files a/icons/title_shadow_minimize@2x.png and b/icons/title_shadow_minimize@2x.png differ diff --git a/icons/title_shadow_minimize@3x.png b/icons/title_shadow_minimize@3x.png index 73bbae0..adcfe34 100644 Binary files a/icons/title_shadow_minimize@3x.png and b/icons/title_shadow_minimize@3x.png differ diff --git a/icons/title_shadow_restore.png b/icons/title_shadow_restore.png index a8d8a69..2ee5a32 100644 Binary files a/icons/title_shadow_restore.png and b/icons/title_shadow_restore.png differ diff --git a/icons/title_shadow_restore@2x.png b/icons/title_shadow_restore@2x.png index 954e309..4880580 100644 Binary files a/icons/title_shadow_restore@2x.png and b/icons/title_shadow_restore@2x.png differ diff --git a/icons/title_shadow_restore@3x.png b/icons/title_shadow_restore@3x.png index cb97cf5..a4af410 100644 Binary files a/icons/title_shadow_restore@3x.png and b/icons/title_shadow_restore@3x.png differ diff --git a/ui/abstract_button.cpp b/ui/abstract_button.cpp index 61eac90..8767ce1 100644 --- a/ui/abstract_button.cpp +++ b/ui/abstract_button.cpp @@ -104,18 +104,20 @@ void AbstractButton::setPointerCursor(bool enablePointerCursor) { } void AbstractButton::setOver(bool over, StateChangeSource source) { - if (over && !(_state & StateFlag::Over)) { - auto was = _state; + if (over == isOver()) { + return; + } + const auto was = _state; + if (over) { _state |= StateFlag::Over; Integration::Instance().registerLeaveSubscription(this); - onStateChanged(was, source); - } else if (!over && (_state & StateFlag::Over)) { - auto was = _state; + } else { _state &= ~State(StateFlag::Over); Integration::Instance().unregisterLeaveSubscription(this); - onStateChanged(was, source); } + onStateChanged(was, source); updateCursor(); + update(); } bool AbstractButton::setDown( @@ -149,8 +151,11 @@ bool AbstractButton::setDown( } void AbstractButton::updateCursor() { - auto pointerCursor = _enablePointerCursor && (_state & StateFlag::Over); - setCursor(pointerCursor ? style::cur_pointer : style::cur_default); + const auto pointerCursor = _enablePointerCursor && isOver(); + if (_pointerCursor != pointerCursor) { + _pointerCursor = pointerCursor; + setCursor(_pointerCursor ? style::cur_pointer : style::cur_default); + } } void AbstractButton::setDisabled(bool disabled) { diff --git a/ui/abstract_button.h b/ui/abstract_button.h index 2710de9..7673827 100644 --- a/ui/abstract_button.h +++ b/ui/abstract_button.h @@ -16,22 +16,29 @@ class AbstractButton : public RpWidget { public: AbstractButton(QWidget *parent); - Qt::KeyboardModifiers clickModifiers() const { + [[nodiscard]] Qt::KeyboardModifiers clickModifiers() const { return _modifiers; } void setDisabled(bool disabled = true); virtual void clearState(); - bool isOver() const { + [[nodiscard]] bool isOver() const { return _state & StateFlag::Over; } - bool isDown() const { + [[nodiscard]] bool isDown() const { return _state & StateFlag::Down; } - bool isDisabled() const { + [[nodiscard]] bool isDisabled() const { return _state & StateFlag::Disabled; } + void setSynteticOver(bool over) { + setOver(over, StateChangeSource::ByPress); + } + void setSynteticDown(bool down, Qt::MouseButton button = Qt::LeftButton) { + setDown(down, StateChangeSource::ByPress, {}, button); + } + void setPointerCursor(bool enablePointerCursor); void setAcceptBoth(bool acceptBoth = true); @@ -95,9 +102,10 @@ private: State _state = StateFlag::None; - bool _acceptBoth = false; Qt::KeyboardModifiers _modifiers; bool _enablePointerCursor = true; + bool _pointerCursor = false; + bool _acceptBoth = false; Fn _clickedCallback; diff --git a/ui/animated_icon.cpp b/ui/animated_icon.cpp new file mode 100644 index 0000000..d0e7699 --- /dev/null +++ b/ui/animated_icon.cpp @@ -0,0 +1,400 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/animated_icon.h" + +#include "ui/image/image_prepare.h" +#include "ui/style/style_core.h" +#include "ui/effects/frame_generator.h" + +#include +#include +#include +#include + +namespace Ui { +namespace { + +constexpr auto kDefaultDuration = crl::time(800); + +} // namespace + +struct AnimatedIcon::Frame { + FrameGenerator::Frame generated; + QImage resizedImage; + int index = 0; +}; + +class AnimatedIcon::Impl final : public std::enable_shared_from_this { +public: + explicit Impl(base::weak_ptr weak); + + void prepareFromAsync( + FnMut()> factory, + QSize sizeOverride); + void waitTillPrepared() const; + + [[nodiscard]] bool valid() const; + [[nodiscard]] QSize size() const; + [[nodiscard]] int framesCount() const; + [[nodiscard]] double frameRate() const; + [[nodiscard]] Frame &frame(); + [[nodiscard]] const Frame &frame() const; + + [[nodiscard]] crl::time animationDuration() const; + void moveToFrame(int frame, QSize updatedDesiredSize); + +private: + enum class PreloadState { + None, + Preloading, + Ready, + }; + + // Called from crl::async. + void renderPreloadFrame(); + + std::unique_ptr _generator; + Frame _current; + QSize _desiredSize; + std::atomic _preloadState = PreloadState::None; + + Frame _preloaded; // Changed on main or async depending on _preloadState. + QSize _preloadImageSize; + + base::weak_ptr _weak; + int _framesCount = 0; + double _frameRate = 0.; + mutable crl::semaphore _semaphore; + mutable bool _ready = false; + +}; + +AnimatedIcon::Impl::Impl(base::weak_ptr weak) +: _weak(weak) { +} + +void AnimatedIcon::Impl::prepareFromAsync( + FnMut()> factory, + QSize sizeOverride) { + const auto guard = gsl::finally([&] { _semaphore.release(); }); + if (!_weak) { + return; + } + auto generator = factory ? factory() : nullptr; + if (!generator || !_weak) { + return; + } + _framesCount = generator->count(); + _frameRate = generator->rate(); + _current.generated = generator->renderNext(QImage(), sizeOverride); + if (_current.generated.image.isNull()) { + return; + } + _generator = std::move(generator); + _desiredSize = sizeOverride.isEmpty() + ? style::ConvertScale(_current.generated.image.size()) + : sizeOverride; +} + +void AnimatedIcon::Impl::waitTillPrepared() const { + if (!_ready) { + _semaphore.acquire(); + _ready = true; + } +} + +bool AnimatedIcon::Impl::valid() const { + waitTillPrepared(); + return (_generator != nullptr); +} + +QSize AnimatedIcon::Impl::size() const { + waitTillPrepared(); + return _desiredSize; +} + +int AnimatedIcon::Impl::framesCount() const { + waitTillPrepared(); + return _framesCount; +} + +double AnimatedIcon::Impl::frameRate() const { + waitTillPrepared(); + return _frameRate; +} + +AnimatedIcon::Frame &AnimatedIcon::Impl::frame() { + waitTillPrepared(); + return _current; +} + +const AnimatedIcon::Frame &AnimatedIcon::Impl::frame() const { + waitTillPrepared(); + return _current; +} + +crl::time AnimatedIcon::Impl::animationDuration() const { + waitTillPrepared(); + const auto rate = _generator ? _generator->rate() : 0.; + const auto frames = _generator ? _generator->count() : 0; + return (frames && rate >= 1.) + ? crl::time(base::SafeRound(frames / rate * 1000.)) + : 0; +} + +void AnimatedIcon::Impl::moveToFrame(int frame, QSize updatedDesiredSize) { + waitTillPrepared(); + const auto state = _preloadState.load(); + const auto shown = _current.index; + if (!updatedDesiredSize.isEmpty()) { + _desiredSize = updatedDesiredSize; + } + const auto desiredImageSize = _desiredSize * style::DevicePixelRatio(); + if (!_generator + || state == PreloadState::Preloading + || (shown == frame + && (_current.generated.image.size() == desiredImageSize))) { + return; + } else if (state == PreloadState::Ready) { + if (_preloaded.index == frame + && (shown != frame + || _preloaded.generated.image.size() == desiredImageSize)) { + std::swap(_current, _preloaded); + if (_current.generated.image.size() == desiredImageSize) { + return; + } + } else if ((shown < _preloaded.index && _preloaded.index < frame) + || (shown > _preloaded.index && _preloaded.index > frame)) { + std::swap(_current, _preloaded); + } + } + _preloadImageSize = desiredImageSize; + _preloaded.index = frame; + _preloadState = PreloadState::Preloading; + crl::async([guard = shared_from_this()] { + guard->renderPreloadFrame(); + }); +} + +void AnimatedIcon::Impl::renderPreloadFrame() { + if (!_weak) { + return; + } + if (_preloaded.index == 0) { + _generator->jumpToStart(); + } + _preloaded.generated = (_preloaded.index && _preloaded.index == _current.index) + ? _generator->renderCurrent( + std::move(_preloaded.generated.image), + _preloadImageSize) + : _generator->renderNext( + std::move(_preloaded.generated.image), + _preloadImageSize); + _preloaded.resizedImage = QImage(); + _preloadState = PreloadState::Ready; + crl::on_main(_weak, [=] { + _weak->frameJumpFinished(); + }); +} + +AnimatedIcon::AnimatedIcon(AnimatedIconDescriptor &&descriptor) +: _impl(std::make_shared(base::make_weak(this))) +, _colorized(descriptor.colorized) { + crl::async([ + impl = _impl, + factory = std::move(descriptor.generator), + sizeOverride = descriptor.sizeOverride + ]() mutable { + impl->prepareFromAsync(std::move(factory), sizeOverride); + }); +} + +void AnimatedIcon::wait() const { + _impl->waitTillPrepared(); +} + +bool AnimatedIcon::valid() const { + return _impl->valid(); +} + +int AnimatedIcon::frameIndex() const { + return _impl->frame().index; +} + +int AnimatedIcon::framesCount() const { + return _impl->framesCount(); +} + +double AnimatedIcon::frameRate() const { + return _impl->frameRate(); +} + +QImage AnimatedIcon::frame(const QColor &textColor) const { + return frame(textColor, QSize(), nullptr).image; +} + +QImage AnimatedIcon::notColorizedFrame() const { + return notColorizedFrame(QSize(), nullptr).image; +} + +AnimatedIcon::ResizedFrame AnimatedIcon::frame( + const QColor &textColor, + QSize desiredSize, + Fn updateWithPerfect) const { + auto result = notColorizedFrame( + desiredSize, + std::move(updateWithPerfect)); + if (_colorized) { + auto &image = result.image; + style::colorizeImage(image, textColor, &image, {}, {}, true); + } + return result; +} + +AnimatedIcon::ResizedFrame AnimatedIcon::notColorizedFrame( + QSize desiredSize, + Fn updateWithPerfect) const { + auto &frame = _impl->frame(); + preloadNextFrame(crl::now(), &frame, desiredSize); + const auto desired = size() * style::DevicePixelRatio(); + if (frame.generated.image.isNull()) { + return { frame.generated.image }; + } else if (frame.generated.image.size() == desired) { + return { frame.generated.image }; + } else if (frame.resizedImage.size() != desired) { + frame.resizedImage = frame.generated.image.scaled( + desired, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + } + if (updateWithPerfect) { + _repaint = std::move(updateWithPerfect); + } + return { frame.resizedImage, true }; +} + +int AnimatedIcon::width() const { + return size().width(); +} + +int AnimatedIcon::height() const { + return size().height(); +} + +QSize AnimatedIcon::size() const { + return _impl->size(); +} + +void AnimatedIcon::paint(QPainter &p, int x, int y) { + auto &frame = _impl->frame(); + preloadNextFrame(crl::now(), &frame); + if (frame.generated.image.isNull()) { + return; + } + const auto rect = QRect{ QPoint(x, y), size() }; + p.drawImage(rect, frame.generated.image); +} + +void AnimatedIcon::paintInCenter(QPainter &p, QRect rect) { + const auto my = size(); + paint( + p, + rect.x() + (rect.width() - my.width()) / 2, + rect.y() + (rect.height() - my.height()) / 2); +} + +void AnimatedIcon::animate(Fn update) { + if (framesCount() != 1 && !anim::Disabled()) { + jumpToStart(std::move(update)); + _animationDuration = _impl->animationDuration(); + _animationCurrentStart = _animationStarted = crl::now(); + continueAnimation(_animationCurrentStart); + } +} + +void AnimatedIcon::continueAnimation(crl::time now) { + const auto callback = [=](float64 value) { + if (anim::Disabled()) { + return; + } + const auto elapsed = int(value); + const auto now = _animationStartTime + elapsed; + if (!_animationDuration && elapsed > kDefaultDuration / 2) { + auto animation = std::move(_animation); + continueAnimation(now); + } + preloadNextFrame(now); + if (_repaint) _repaint(); + }; + const auto duration = _animationDuration + ? _animationDuration + : kDefaultDuration; + _animationStartTime = now; + _animation.start(callback, 0., 1. * duration, duration); +} + +void AnimatedIcon::jumpToStart(Fn update) { + _repaint = std::move(update); + _animation.stop(); + _animationCurrentIndex = 0; + _impl->moveToFrame(0, QSize()); +} + +void AnimatedIcon::frameJumpFinished() { + if (_repaint && !animating()) { + _repaint(); + _repaint = nullptr; + } +} + +int AnimatedIcon::wantedFrameIndex( + crl::time now, + const Frame *resolvedCurrent) const { + const auto frame = resolvedCurrent ? resolvedCurrent : &_impl->frame(); + if (frame->index == _animationCurrentIndex + 1) { + ++_animationCurrentIndex; + _animationCurrentStart = _animationNextStart; + } + if (!_animation.animating()) { + return _animationCurrentIndex; + } + if (frame->index == _animationCurrentIndex) { + const auto duration = frame->generated.duration; + const auto next = _animationCurrentStart + duration; + if (frame->generated.last) { + _animation.stop(); + if (_repaint) _repaint(); + return _animationCurrentIndex; + } else if (now < next) { + return _animationCurrentIndex; + } + _animationNextStart = next; + return _animationCurrentIndex + 1; + } + Assert(!_animationCurrentIndex); + return 0; +} + +void AnimatedIcon::preloadNextFrame( + crl::time now, + const Frame *resolvedCurrent, + QSize updatedDesiredSize) const { + _impl->moveToFrame( + wantedFrameIndex(now, resolvedCurrent), + updatedDesiredSize); +} + +bool AnimatedIcon::animating() const { + return _animation.animating(); +} + +std::unique_ptr MakeAnimatedIcon( + AnimatedIconDescriptor &&descriptor) { + return std::make_unique(std::move(descriptor)); +} + +} // namespace Lottie diff --git a/ui/animated_icon.h b/ui/animated_icon.h new file mode 100644 index 0000000..5c58f28 --- /dev/null +++ b/ui/animated_icon.h @@ -0,0 +1,97 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +#include "ui/style/style_core_types.h" +#include "ui/effects/animations.h" +#include "base/weak_ptr.h" + +#include +#include +#include + +namespace Ui { + +class FrameGenerator; + +struct AnimatedIconDescriptor { + FnMut()> generator; + QSize sizeOverride; + bool colorized = false; +}; + +class AnimatedIcon final : public base::has_weak_ptr { +public: + explicit AnimatedIcon(AnimatedIconDescriptor &&descriptor); + AnimatedIcon(const AnimatedIcon &other) = delete; + AnimatedIcon &operator=(const AnimatedIcon &other) = delete; + AnimatedIcon(AnimatedIcon &&other) = delete; // _animation captures this. + AnimatedIcon &operator=(AnimatedIcon &&other) = delete; + + [[nodiscard]] bool valid() const; + [[nodiscard]] int frameIndex() const; + [[nodiscard]] int framesCount() const; + [[nodiscard]] double frameRate() const; + [[nodiscard]] QImage frame(const QColor &textColor) const; + [[nodiscard]] QImage notColorizedFrame() const; + [[nodiscard]] int width() const; + [[nodiscard]] int height() const; + [[nodiscard]] QSize size() const; + + struct ResizedFrame { + QImage image; + bool scaled = false; + }; + [[nodiscard]] ResizedFrame frame( + const QColor &textColor, + QSize desiredSize, + Fn updateWithPerfect) const; + [[nodiscard]] ResizedFrame notColorizedFrame( + QSize desiredSize, + Fn updateWithPerfect) const; + + void animate(Fn update); + void jumpToStart(Fn update); + + void paint(QPainter &p, int x, int y); + void paintInCenter(QPainter &p, QRect rect); + + [[nodiscard]] bool animating() const; + +private: + struct Frame; + class Impl; + friend class Impl; + + void wait() const; + [[nodiscard]] int wantedFrameIndex( + crl::time now, + const Frame *resolvedCurrent = nullptr) const; + void preloadNextFrame( + crl::time now, + const Frame *resolvedCurrent = nullptr, + QSize updatedDesiredSize = QSize()) const; + void frameJumpFinished(); + void continueAnimation(crl::time now); + + std::shared_ptr _impl; + crl::time _animationStartTime = 0; + crl::time _animationStarted = 0; + mutable Animations::Simple _animation; + mutable Fn _repaint; + mutable crl::time _animationDuration = 0; + mutable crl::time _animationCurrentStart = 0; + mutable crl::time _animationNextStart = 0; + mutable int _animationCurrentIndex = 0; + bool _colorized = false; + +}; + +[[nodiscard]] std::unique_ptr MakeAnimatedIcon( + AnimatedIconDescriptor &&descriptor); + +} // namespace Ui diff --git a/ui/basic.style b/ui/basic.style index 57d56d0..8d55bac 100644 --- a/ui/basic.style +++ b/ui/basic.style @@ -9,31 +9,47 @@ using "ui/colors.palette"; TextPalette { linkFg: color; monoFg: color; + spoilerFg: color; selectBg: color; selectFg: color; selectLinkFg: color; selectMonoFg: color; + selectSpoilerFg: color; selectOverlay: color; - linkAlwaysActive: int; - spoilerBg: color; - spoilerActiveBg: color; - spoilerActiveFg: color; + linkAlwaysActive: bool; +} + +QuoteStyle { + padding: margins; + verticalSkip: pixels; + header: pixels; + headerPosition: point; + icon: icon; + iconPosition: point; + outline: pixels; + outlineShift: pixels; + radius: pixels; + scrollable: bool; } TextStyle { font: font; - linkFont: font; - linkFontOver: font; + linkUnderline: int; lineHeight: pixels; + blockquote: QuoteStyle; + pre: QuoteStyle; } +kLinkUnderlineNever: 0; +kLinkUnderlineActive: 1; +kLinkUnderlineAlways: 2; + fsize: 13px; normalFont: font(fsize); semiboldFont: font(fsize semibold); boxFontSize: 14px; boxTextFont: font(boxFontSize); -emojiImgSize: 18px; // exceptional value for retina emojiSize: 18px; emojiPadding: 1px; @@ -42,29 +58,27 @@ lineWidth: 1px; defaultTextPalette: TextPalette { linkFg: windowActiveTextFg; monoFg: msgInMonoFg; + spoilerFg: msgInDateFg; selectBg: msgInBgSelected; selectFg: transparent; // use painter current pen instead selectLinkFg: historyLinkInFgSelected; selectMonoFg: msgInMonoFgSelected; + selectSpoilerFg: msgInDateFgSelected; selectOverlay: msgSelectOverlay; - spoilerBg: msgInDateFg; - spoilerActiveBg: msgInDateFg; - spoilerActiveFg: msgInBg; +} +defaultQuoteStyle: QuoteStyle { } defaultTextStyle: TextStyle { font: normalFont; - linkFont: normalFont; - linkFontOver: font(fsize underline); + linkUnderline: kLinkUnderlineActive; lineHeight: 0px; + blockquote: defaultQuoteStyle; + pre: defaultQuoteStyle; } semiboldTextStyle: TextStyle(defaultTextStyle) { font: semiboldFont; - linkFont: semiboldFont; - linkFontOver: font(fsize semibold underline); } -shadowToggleDuration: 200; - slideDuration: 240; slideShift: 100px; slideShadow: icon {{ "slide_shadow", slideFadeOutShadowFg }}; @@ -74,15 +88,13 @@ fadeWrapDuration: 200; linkCropLimit: 360px; linkFont: normalFont; -linkOverFont: font(fsize underline); +linkFontOver: font(fsize underline); roundRadiusLarge: 6px; roundRadiusSmall: 3px; dateRadius: roundRadiusLarge; -setLittleSkip: 9px; - noContactsHeight: 100px; noContactsFont: font(fsize); noContactsColor: windowSubTextFg; @@ -90,170 +102,8 @@ noContactsColor: windowSubTextFg; activeFadeInDuration: 500; activeFadeOutDuration: 3000; -msgMaxWidth: 430px; -msgFont: font(fsize); -msgNameFont: semiboldFont; -msgNameStyle: semiboldTextStyle; -msgServiceFont: semiboldFont; -msgServiceNameFont: semiboldFont; -msgServicePhotoWidth: 100px; -msgDateFont: font(13px); -msgMinWidth: 160px; -msgPhotoSize: 33px; -msgPhotoSkip: 40px; -msgPadding: margins(13px, 7px, 13px, 8px); -msgMargin: margins(16px, 6px, 56px, 2px); -msgMarginTopAttached: 1px; -msgLnkPadding: 2px; // for media open / save links -msgShadow: 2px; - -msgReplyPadding: margins(6px, 6px, 11px, 6px); -msgReplyBarPos: point(1px, 0px); -msgReplyBarSize: size(2px, 36px); -msgReplyBarSkip: 10px; -msgServicePadding: margins(12px, 3px, 12px, 4px); -msgServiceMargin: margins(10px, 10px, 10px, 2px); - -msgDateSpace: 12px; -msgDateDelta: point(2px, 5px); - -msgDateImgDelta: 4px; -msgDateImgPadding: point(8px, 2px); -msgDateImgCheckSpace: 4px; - -messageTextStyle: defaultTextStyle; -msgDateTextStyle: defaultTextStyle; -serviceTextPalette: TextPalette(defaultTextPalette) { - linkFg: msgServiceFg; - monoFg: msgServiceFg; - selectBg: msgServiceBgSelected; - selectFg: msgServiceFg; - selectLinkFg: msgServiceFg; - selectMonoFg: msgServiceFg; - selectOverlay: msgServiceBgSelected; -} -serviceTextStyle: TextStyle(defaultTextStyle) { - font: msgServiceFont; - linkFont: msgServiceFont; - linkFontOver: font(fsize semibold underline); -} -inTextPalette: TextPalette(defaultTextPalette) { - linkFg: historyLinkInFg; - monoFg: msgInMonoFg; - selectBg: msgInBgSelected; - selectFg: historyTextInFgSelected; - selectLinkFg: historyLinkInFgSelected; - selectMonoFg: msgInMonoFgSelected; - selectOverlay: msgSelectOverlay; - spoilerBg: msgInDateFg; - spoilerActiveBg: msgInDateFg; - spoilerActiveFg: msgInBg; -} -inTextPaletteSelected: TextPalette(inTextPalette) { - linkFg: historyLinkInFgSelected; - monoFg: msgInMonoFgSelected; -} -outTextPalette: TextPalette(defaultTextPalette) { - linkFg: historyLinkOutFg; - monoFg: msgOutMonoFg; - selectBg: msgOutBgSelected; - selectFg: historyTextOutFgSelected; - selectLinkFg: historyLinkOutFgSelected; - selectMonoFg: msgOutMonoFgSelected; - selectOverlay: msgSelectOverlay; - spoilerBg: msgOutDateFg; - spoilerActiveBg: msgOutDateFg; - spoilerActiveFg: msgOutBg; -} -outTextPaletteSelected: TextPalette(outTextPalette) { - linkFg: historyLinkOutFgSelected; - monoFg: msgOutMonoFgSelected; -} -fwdTextStyle: TextStyle(semiboldTextStyle) { - linkFontOver: semiboldFont; -} -inFwdTextPalette: TextPalette(defaultTextPalette) { - linkFg: msgInServiceFg; -} -outFwdTextPalette: TextPalette(defaultTextPalette) { - linkFg: msgOutServiceFg; -} -inFwdTextPaletteSelected: TextPalette(defaultTextPalette) { - linkFg: msgInServiceFgSelected; -} -outFwdTextPaletteSelected: TextPalette(defaultTextPalette) { - linkFg: msgOutServiceFgSelected; -} -inReplyTextPalette: TextPalette(inTextPalette) { - linkFg: msgInDateFg; -} -inReplyTextPaletteSelected: TextPalette(inTextPaletteSelected) { - linkFg: msgInDateFgSelected; -} -outReplyTextPalette: TextPalette(outTextPalette) { - linkFg: msgOutDateFg; -} -outReplyTextPaletteSelected: TextPalette(outTextPaletteSelected) { - linkFg: msgOutDateFgSelected; -} -imgReplyTextPalette: TextPalette(defaultTextPalette) { - linkFg: msgImgReplyBarColor; -} -inSemiboldPalette: TextPalette(inTextPalette) { - linkFg: msgInServiceFg; - selectFg: msgInServiceFgSelected; - selectLinkFg: msgInServiceFgSelected; -} -outSemiboldPalette: TextPalette(outTextPalette) { - linkFg: msgOutServiceFg; - selectFg: msgOutServiceFgSelected; - selectLinkFg: msgOutServiceFgSelected; -} -historyComposeAreaPalette: TextPalette(defaultTextPalette) { - linkFg: historyComposeAreaFgService; -} - -mediaCaptionSkip: 5px; -mediaInBubbleSkip: 5px; -mediaThumbSize: 48px; -mediaNameTop: 3px; -mediaDetailsShift: 3px; -mediaUnreadSize: 7px; -mediaUnreadSkip: 5px; -mediaUnreadTop: 6px; - -mediaInPalette: TextPalette(defaultTextPalette) { - linkFg: mediaInFg; -} -mediaInPaletteSelected: TextPalette(defaultTextPalette) { - linkFg: mediaInFgSelected; -} - -textRectMargins: margins(-2px, -1px, -2px, -1px); - -searchedBarHeight: 32px; -searchedBarFont: normalFont; -searchedBarPosition: point(17px, 7px); - smallCloseIcon: icon {{ "simple_close", smallCloseIconFg }}; smallCloseIconOver: icon {{ "simple_close", smallCloseIconFgOver }}; -dialogsForwardCancelIcon: icon {{ "simple_close", dialogsForwardFg }}; - -emojiTextFont: font(15px); -emojiReplaceWidth: 52px; -emojiReplaceHeight: 56px; -emojiReplaceInnerHeight: 42px; -emojiReplacePadding: 14px; - -dragFont: font(27px semibold); -dragSubfont: font(19px semibold); -dragColor: windowSubTextFg; -dragDropColor: windowActiveTextFg; - -dragMargin: margins(0px, 10px, 0px, 10px); -dragPadding: margins(20px, 10px, 20px, 10px); - -dragHeight: 72px; radialSize: size(50px, 50px); radialLine: 3px; @@ -261,40 +111,13 @@ radialDuration: 350; radialPeriod: 3000; locationSize: size(320px, 240px); -mediaPlayerSuppressDuration: 150; - -botDescSkip: 8px; - -inlineResultsLeft: 11px; -inlineResultsSkip: 3px; -inlineMediaHeight: 96px; -inlineThumbSize: 64px; -inlineThumbSkip: 10px; -inlineTitleFg: windowFg; -inlineDescriptionFg: windowSubTextFg; -inlineRowMargin: 6px; -inlineRowBorder: 1px; -inlineRowBorderFg: shadowFg; -inlineRowFileNameTop: 2px; -inlineRowFileDescriptionTop: 23px; -inlineResultsMinWidth: 48px; -inlineDurationMargin: 3px; - -historyReplyCancelIcon: icon {{ "box_button_close", historyReplyCancelFg }}; -historyReplyCancelIconOver: icon {{ "box_button_close", historyReplyCancelFgOver }}; -boxTitleCloseIcon: icon {{ "box_button_close", boxTitleCloseFg }}; -boxTitleCloseIconOver: icon {{ "box_button_close", boxTitleCloseFgOver }}; - -notifyFadeRight: icon {{ "fade_horizontal", notificationBg }}; - -stickerIconLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }}; -stickerIconRight: icon {{ "fade_horizontal", emojiPanCategories }}; - -emojiSuggestionsFadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }}; -emojiSuggestionsFadeRight: icon {{ "fade_horizontal", boxBg }}; - transparentPlaceholderSize: 4px; +defaultVerticalListSkip: 6px; + +shakeShift: 4px; +shakeDuration: 300; + // floating badge colors roundedFg: radialFg; roundedBg: radialBg; // closest to #00000066 diff --git a/ui/basic_click_handlers.cpp b/ui/basic_click_handlers.cpp index 71d3da7..32a23a7 100644 --- a/ui/basic_click_handlers.cpp +++ b/ui/basic_click_handlers.cpp @@ -64,11 +64,13 @@ QString UrlClickHandler::EncodeForOpening(const QString &originalUrl) { ? QString::fromUtf8(good.toEncoded()) : originalUrl; + static const auto RegExp = QRegularExpression( + QStringLiteral("^[a-zA-Z]+:")); + if (!result.isEmpty() - && !QRegularExpression( - QStringLiteral("^[a-zA-Z]+:")).match(result).hasMatch()) { + && !RegExp.match(result).hasMatch()) { // No protocol. - return QStringLiteral("http://") + result; + return QStringLiteral("https://") + result; } return result; } diff --git a/ui/basic_click_handlers.h b/ui/basic_click_handlers.h index ac8c7e3..178e68c 100644 --- a/ui/basic_click_handlers.h +++ b/ui/basic_click_handlers.h @@ -28,7 +28,6 @@ public: } protected: - virtual QString url() const = 0; virtual QString readable() const; bool _fullDisplayed; @@ -39,6 +38,10 @@ class UrlClickHandler : public TextClickHandler { public: UrlClickHandler(const QString &url, bool fullDisplayed = true); + [[nodiscard]] QString originalUrl() const { + return _originalUrl; + } + QString copyToClipboardContextItemText() const override; QString dragText() const override { @@ -64,9 +67,6 @@ public: [[nodiscard]] static QString ShowEncoded(const QString &url); protected: - [[nodiscard]] QString originalUrl() const { - return _originalUrl; - } QString url() const override { return EncodeForOpening(_originalUrl); } diff --git a/ui/cached_special_layer_shadow_corners.cpp b/ui/cached_special_layer_shadow_corners.cpp new file mode 100644 index 0000000..0d98360 --- /dev/null +++ b/ui/cached_special_layer_shadow_corners.cpp @@ -0,0 +1,71 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/cached_special_layer_shadow_corners.h" + +#include "ui/effects/ripple_animation.h" +#include "styles/style_layers.h" + +namespace Ui { +namespace { + +[[nodiscard]] std::array PrepareSpecialLayerShadowCorners() { + const auto &st = st::boxRoundShadow; + + const auto s = QSize( + st::boxRadius * 2 + st.extend.left(), + st::boxRadius * 2 + st.extend.right()); + const auto mask = Ui::RippleAnimation::MaskByDrawer(s, false, [&]( + QPainter &p) { + p.drawRoundedRect(QRect(QPoint(), s), st::boxRadius, st::boxRadius); + }); + struct Corner { + const style::icon &icon; + QPoint factor; + }; + const auto corners = std::vector{ + Corner{ st.topLeft, QPoint(1, 1) }, + Corner{ st.bottomLeft, QPoint(1, 0) }, + Corner{ st.topRight, QPoint(0, 1) }, + Corner{ st.bottomRight, QPoint(0, 0) }, + }; + const auto processCorner = [&](int i) { + const auto &corner = corners[i]; + auto result = QImage( + corner.icon.size() * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied); + result.setDevicePixelRatio(style::DevicePixelRatio()); + result.fill(Qt::transparent); + + { + QPainter p(&result); + corner.icon.paint(p, 0, 0, corner.icon.width()); + p.setCompositionMode(QPainter::CompositionMode_DestinationOut); + p.drawImage( + corner.icon.width() * corner.factor.x() + - mask.width() / style::DevicePixelRatio() / 2, + corner.icon.height() * corner.factor.y() + - mask.height() / style::DevicePixelRatio() / 2, + mask); + } + return result; + }; + return std::array{ { + processCorner(0), + processCorner(1), + processCorner(2), + processCorner(3), + } }; +} + +} // namespace + +const std::array &SpecialLayerShadowCorners() { + static const auto custom = PrepareSpecialLayerShadowCorners(); + return custom; +} + +} // namespace Ui diff --git a/ui/cached_special_layer_shadow_corners.h b/ui/cached_special_layer_shadow_corners.h new file mode 100644 index 0000000..10955d4 --- /dev/null +++ b/ui/cached_special_layer_shadow_corners.h @@ -0,0 +1,13 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +namespace Ui { + +[[nodiscard]] const std::array &SpecialLayerShadowCorners(); + +} // namespace Ui diff --git a/ui/click_handler.cpp b/ui/click_handler.cpp index f5129cb..4cb8ae2 100644 --- a/ui/click_handler.cpp +++ b/ui/click_handler.cpp @@ -8,6 +8,7 @@ #include "base/algorithm.h" #include "ui/text/text_entity.h" +#include "ui/integration.h" #include @@ -170,7 +171,9 @@ void ActivateClickHandler( ClickContext context) { crl::on_main(guard, [=, weak = std::weak_ptr(handler)] { if (const auto strong = weak.lock()) { - strong->onClick(context); + if (Ui::Integration::Instance().allowClickHandlerActivation(strong, context)) { + strong->onClick(context); + } } }); } diff --git a/ui/click_handler.h b/ui/click_handler.h index 9e1b0b9..08151b5 100644 --- a/ui/click_handler.h +++ b/ui/click_handler.h @@ -38,6 +38,11 @@ public: virtual void onClick(ClickContext context) const = 0; + // Some sort of `id`, for text links contains urls. + virtual QString url() const { + return QString(); + } + // What text to show in a tooltip when mouse is over that click handler as a link in Text. virtual QString tooltip() const { return QString(); @@ -109,16 +114,16 @@ protected: }; -class LambdaClickHandler : public ClickHandler { +class GenericClickHandler : public ClickHandler { public: - LambdaClickHandler(Fn handler) + GenericClickHandler(Fn handler) : _handler([handler = std::move(handler)](ClickContext) { handler(); }) { } - LambdaClickHandler(Fn handler) + GenericClickHandler(Fn handler) : _handler(std::move(handler)) { } - void onClick(ClickContext context) const override final { - if (context.button == Qt::LeftButton && _handler) { + void onClick(ClickContext context) const override { + if (_handler) { _handler(context); } } @@ -128,6 +133,18 @@ private: }; +class LambdaClickHandler : public GenericClickHandler { +public: + using GenericClickHandler::GenericClickHandler; + + void onClick(ClickContext context) const override final { + if (context.button == Qt::LeftButton) { + GenericClickHandler::onClick(std::move(context)); + } + } + +}; + void ActivateClickHandler( not_null guard, ClickHandlerPtr handler, diff --git a/ui/colors.palette b/ui/colors.palette index 8d57cce..71081e0 100644 --- a/ui/colors.palette +++ b/ui/colors.palette @@ -53,9 +53,9 @@ attentionButtonBgRipple: #f4c3c2; // default attention button ripple effect menuBg: windowBg; // default popup menu background menuBgOver: windowBgOver; // default popup menu item background with mouse over menuBgRipple: windowBgRipple; // default popup menu item ripple effect -menuIconFg: #a8a8a8; // default popup menu item icon (like main menu) -menuIconFgOver: #999999; // default popup menu item icon with mouse over -menuSubmenuArrowFg: #666B72; // default popup menu submenu arrow icon (like in message field context menu in case of RTL system language) +menuIconFg: #999999; // default popup menu item icon (like main menu) +menuIconFgOver: #8a8a8a; // default popup menu item icon with mouse over +menuSubmenuArrowFg: #373737; // default popup menu submenu arrow icon (like in message field context menu in case of RTL system language) menuFgDisabled: #cccccc; // default popup menu item disabled text (like unavailable items in message field context menu) menuSeparatorFg: #f1f1f1; // default popup menu separator (like in message field context menu) @@ -161,7 +161,6 @@ callArrowMissedFg: #dd5b4a | boxTextFgError; // missed phone call arrow (in call introBg: windowBg; // login background introTitleFg: windowBoldFg; // login title text introDescriptionFg: windowSubTextFg; // login description text -introErrorFg: windowSubTextFg; // login error text (like when providing a wrong log in code) introCoverTopBg: #0f89d0; // intro gradient top (from) introCoverBottomBg: #39b0f0; // intro gradient bottom (to) @@ -230,9 +229,6 @@ dialogsScamFgActive: dialogsDraftFgActive; // chat list scam label for current ( dialogsRippleBg: windowBgRipple; // chat list background ripple effect dialogsRippleBgActive: activeButtonBgRipple; // chat list background ripple effect for current (active) chat -dialogsForwardBg: dialogsBgActive; // forwarding panel background (when forwarding messages in the smallest window size) -dialogsForwardFg: dialogsNameFgActive; // forwarding panel text (when forwarding messages in the smallest window size) - searchedBarBg: windowBgOver; // search results bar background (in chats list, contacts box..) searchedBarFg: windowSubTextFgOver; // search results bar text (in chats list, contacts box..) @@ -243,11 +239,13 @@ emojiPanBg: windowBg; // emoji panel background emojiPanCategories: #f7f7f7 | windowBg; // emoji panel categories background emojiPanHeaderFg: windowSubTextFg; // emoji panel section header text emojiPanHeaderBg: #fffffff2 | emojiPanBg; // emoji panel section header background -emojiIconFg: checkboxFg; // emoji category icon -emojiIconFgActive: windowBgActive; // active emoji category icon +emojiIconFg: #999999; // emoji category icon +emojiSubIconFgActive: #666666 | windowBoldFg; // active emoji subcategory icon stickerPanDeleteBg: #000000ff; // delete X button background for custom sent stickers in stickers panel (legacy) stickerPanDeleteFg: windowFgActive; // delete X button icon for custom sent stickers in stickers panel (legacy) stickerPreviewBg: #ffffffb0; // sticker and GIF preview background (when you press and hold on a sticker) +stickerPanPremium1: #5a99ff; // premium sticker pack icon gradient 1 +stickerPanPremium2: #45b9f3; // premium sticker pack icon gradient 2 historyTextInFg: windowFg; // inbox message text historyTextInFgSelected: historyTextInFg; // inbox message selected text or text in a selected message @@ -283,32 +281,52 @@ historyForwardChooseFg: windowFgActive; // forwarding messages in a large window historyPeer1NameFg: #c03d33; // red group member name historyPeer1NameFgSelected: historyPeer1NameFg; // red group member name in a selected message -historyPeer1UserpicBg: #e17076; // red userpic background +historyPeer1UserpicBg: #ff845e; // red userpic background historyPeer2NameFg: #4fad2d; // green group member name historyPeer2NameFgSelected: historyPeer2NameFg; // green group member name in a selected message -historyPeer2UserpicBg: #7bc862; // green userpic background -historyPeer3NameFg: #d09306; // yellow group member name -historyPeer3NameFgSelected: historyPeer3NameFg; // yellow group member name in a selected message -historyPeer3UserpicBg: #e5ca77; // yellow userpic background +historyPeer2UserpicBg: #9ad164; // green userpic background +historyPeer3NameFg: #d09306; // yellow group member name (actually unused) +historyPeer3NameFgSelected: historyPeer3NameFg; // yellow group member name in a selected message (actually unused) +historyPeer3UserpicBg: #e5ca77; // yellow userpic background (actually unused) historyPeer4NameFg: windowActiveTextFg; // blue group member name historyPeer4NameFgSelected: historyPeer4NameFg; // blue group member name in a selected message -historyPeer4UserpicBg: #65aadd; // blue userpic background +historyPeer4UserpicBg: #5caffa; // blue userpic background historyPeer5NameFg: #8544d6; // purple group member name historyPeer5NameFgSelected: historyPeer5NameFg; // purple group member name in a selected message -historyPeer5UserpicBg: #a695e7; // purple userpic background +historyPeer5UserpicBg: #b694f9; // purple userpic background historyPeer6NameFg: #cd4073; // pink group member name historyPeer6NameFgSelected: historyPeer6NameFg; // pink group member name in a selected message -historyPeer6UserpicBg: #ee7aae; // pink userpic background +historyPeer6UserpicBg: #ff8aac; // pink userpic background historyPeer7NameFg: #2996ad; // sea group member name historyPeer7NameFgSelected: historyPeer7NameFg; // sea group member name in a selected message -historyPeer7UserpicBg: #6ec9cb; // sea userpic background +historyPeer7UserpicBg: #5bcbe3; // sea userpic background historyPeer8NameFg: #ce671b; // orange group member name historyPeer8NameFgSelected: historyPeer8NameFg; // orange group member name in a selected message -historyPeer8UserpicBg: #faa774; // orange userpic background +historyPeer8UserpicBg: #febb5b; // orange userpic background historyPeerUserpicFg: windowFgActive; // default userpic initials historyPeerSavedMessagesBg: historyPeer4UserpicBg; // saved messages userpic background historyPeerArchiveUserpicBg: dialogsUnreadBgMuted; // archive folder userpic background +historyPeer1UserpicBg2: #d45246 | historyPeer1UserpicBg; // the second red userpic background +historyPeer2UserpicBg2: #46ba43 | historyPeer2UserpicBg; // the second green userpic background +historyPeer3UserpicBg2: #e5ca77 | historyPeer3UserpicBg; // the second yellow userpic background (actually unused) +historyPeer4UserpicBg2: #408acf | historyPeer4UserpicBg; // the second blue userpic background +historyPeer5UserpicBg2: #6c61df | historyPeer5UserpicBg; // the second purple userpic background +historyPeer6UserpicBg2: #d95574 | historyPeer6UserpicBg; // the second pink userpic background +historyPeer7UserpicBg2: #359ad4 | historyPeer7UserpicBg; // the second sea userpic background +historyPeer8UserpicBg2: #f68136 | historyPeer8UserpicBg; // the second orange userpic background +historyPeerSavedMessagesBg2: historyPeer4UserpicBg2; // the second saved messages userpic background + +settingsIconBg1: #f06964; // red settings icon background +settingsIconBg2: #6dc534; // green settings icon background +settingsIconBg3: #ed9f20; // light-orange settings icon background +settingsIconBg4: #56b3f5; // light-blue settings icon background +settingsIconBg5: #7595ff; // dark-blue settings icon background +settingsIconBg6: #b580e2; // purple settings icon background +settingsIconBg8: #f2925b; // dark-orange settings icon background +settingsIconBgArchive: #9da2b0; // archive main menu icon background +settingsIconFg: #ffffff; // settings icon shape + // Some values are marked as (adjusted), it means they're adjusted by // hue and saturation of the average background color if user chooses // some other (not bundled to this color theme) background. If the @@ -361,7 +379,6 @@ msgFileInBg: windowBgActive; // inbox audio file download circle background msgFileInBgOver: #4eade3; // inbox audio file download circle background with mouse over msgFileInBgSelected: #51a3d3; // inbox selected audio file download circle background msgFileOutBg: #5fbe67; // outbox audio file download circle background -msgFileOutBgOver: #5ab15f; // outbox audio file download circle background with mouse over msgFileOutBgSelected: #50ac9b; // outbox selected audio file download circle background msgFile1Bg: #72b1df; // blue shared links / files without image square thumbnail @@ -418,11 +435,8 @@ youtubePlayIconBg: #e83131c8; // youtube play icon background (when a link to a youtubePlayIconFg: windowFgActive; // youtube play icon arrow (when a link to a youtube video with a webpage preview is sent) videoPlayIconBg: #0000007f; // other video play icon background (like when a link to a vimeo video with a webpage preview is sent) videoPlayIconFg: #ffffff; // other video play icon arrow (like when a link to a vimeo video with a webpage preview is sent) -toastBg: #000000b2; // toast notification background (like when you click on your t.me link when editing your username) -toastFg: windowFgActive; // toast notification text (like when you click on your t.me link when editing your username) - -reportSpamBg: emojiPanHeaderBg; // report spam panel background (like a non contact user writes your for the first time) -reportSpamFg: windowFg; // report spam panel text (when you send a report from that panel) +toastBg: #2c3033e5; // toast notification background (like when you click on your t.me link when editing your username) +toastFg: #ffffff; // toast notification text (like when you click on your t.me link when editing your username) historyToDownBg: windowBg; // arrow button background (to scroll to the end of the viewed chat) historyToDownBgOver: windowBgOver; // arrow button background with mouse over @@ -455,7 +469,6 @@ mapPointDot: #ffffff; // geo location marker point overviewCheckBg: #00000040; // shared media / files / links checkbox background for not selected rows when some rows are selected overviewCheckBgActive: windowBgActive; // shared media / files / links checkbox background for selected rows overviewCheckBorder: windowBg; // shared media round checkbox border -overviewCheckFg: windowBg; // shared files / links checkbox icon for not selected rows when some rows are selected overviewCheckFgActive: windowBg; // shared files / links checkbox icon for selected rows overviewPhotoSelectOverlay: #40ace333; // shared photos / videos / links fill for selected rows @@ -464,9 +477,6 @@ profileStatusFgOver: #7c99b2; // group members list in group profile user last s profileVerifiedCheckBg: windowBgActive; // profile verified check icon background profileVerifiedCheckFg: windowFgActive; // profile verified check icon tick profileAdminStartFg: windowBgActive; // group members list creator star icon -profileAdminStarFgOver: profileAdminStartFg; // group members list creator star icon with mouse over -profileOtherAdminStarFg: windowSubTextFg; // group members list admin star icon -profileOtherAdminStarFgOver: profileStatusFgOver; // group members list admin star icon with mouse over // settings notificationsBoxMonitorFg: windowFg; // custom notifications settings box monitor color @@ -477,12 +487,8 @@ notificationSampleCloseFg: #d7d7d7 | windowSubTextFg; // custom notifications se notificationSampleTextFg: #d7d7d7 | windowSubTextFg; // custom notifications settings box small sample text placeholder notificationSampleNameFg: #939393 | windowSubTextFg; // custom notifications settings box small sample name placeholder -changePhoneSimcardFrom: notificationSampleTextFg; // change phone number box left simcard icon -changePhoneSimcardTo: notificationSampleNameFg; // change phone number box right simcard and plane icons - mainMenuBg: windowBg; // main menu background mainMenuCoverBg: dialogsBgActive; // main menu top cover background -mainMenuCoverFg: windowFgActive; // main menu top cover text mainMenuCloudFg: activeButtonFg; // main menu top cover saved messages / archive button icon mainMenuCloudBg: #2785bf | activeButtonBgRipple; // main menu top cover saved messages / archive button background @@ -509,10 +515,10 @@ mediaviewMenuFg: windowFgActive; // context menu item text mediaviewBg: #222222eb; // Media Viewer background mediaviewVideoBg: imageBg; // Media Viewer background when viewing a video in full screen mediaviewControlBg: #0000003c; // controls background (like next photo / previous photo) -mediaviewControlFg: windowFgActive; // controls icon (like next photo / previous photo) +mediaviewControlFg: #ffffff; // controls icon (like next photo / previous photo) mediaviewCaptionBg: #11111180; // caption text background (when viewing photo with caption) mediaviewCaptionFg: mediaviewControlFg; // caption text -mediaviewTextLinkFg: #91d9ff; // caption text link +mediaviewTextLinkFg: #4db8ff; // caption text link mediaviewSaveMsgBg: toastBg; // save to file toast message background in Media Viewer mediaviewSaveMsgFg: toastFg; // save to file toast message text @@ -527,7 +533,6 @@ mediaviewPlaybackIconRipple: #ffffff14; // video playback controls ripple effect mediaviewPipControlsFg: #ffffffd9; // picture-in-picture controls mediaviewPipControlsFgOver: #ffffff; // picture-in-picture controls with mouse over -mediaviewPipFade: #00000095; // picture-in-picture gradient fade controls background mediaviewPipPlaybackActive: #ffffffda; // picture-in-picture playback progress already played part mediaviewPipPlaybackInactive: #ffffff26; // picture-in-picture playback progress upcoming (not played yet) part @@ -589,7 +594,6 @@ groupCallVideoSubTextFg: #ffffffc0; // group call additional text over video callBarBg: dialogsBgActive; // active phone call bar background callBarMuteRipple: dialogsRippleBgActive; // active phone call bar mute and hangup button ripple effect callBarBgMuted: #8f8f8f | dialogsUnreadBgMuted; // phone call bar with muted mic background -callBarUnmuteRipple: #7f7f7f | shadowFg; // phone call bar with muted mic mute and hangup button ripple effect callBarFg: dialogsNameFgActive; // phone call bar text and icons importantTooltipBg: toastBg; // group call important tooltip background color @@ -641,9 +645,31 @@ sideBarBadgeFg: #ffffff; // filters side bar badge text songCoverOverlayFg: #00000066; // song cover overlay -photoEditorBg: boxTitleAdditionalFg; // photo editor background photoEditorItemBaseHandleFg: #3ccaef; // photo editor handle circle +premiumButtonBg1: #55a5ff; // upgrade to premium button gradient 1 +premiumButtonBg2: #a767ff; // upgrade to premium button gradient 2 +premiumButtonBg3: #db5c9d; // upgrade to premium button gradient 3 +premiumButtonFg: #ffffff; // upgrade to premium button text + +premiumIconBg1: #f38926; // icon in premium settings gradient 1 +premiumIconBg2: #e44456; // icon in premium settings gradient 2 +premiumIconBg3: #4acd43; // icon in premium settings gradient 3 + +statisticsChartInactive: #e2eef999; // inactive area in footer of statistic charts +statisticsChartActive: #baccd9d8; // sides in footer of statistic charts + +statisticsChartLineBlue: #327fe5; // represents blue color on statistical charts +statisticsChartLineGreen: #61c752; // represents green color on statistical charts +statisticsChartLineRed: #e05356; // represents red color on statistical charts +statisticsChartLineGolden: #eba52d; // represents golden color on statistical charts +statisticsChartLineLightblue: #58a8ed; // represents lightblue color on statistical charts +statisticsChartLineLightgreen: #8fcf39; // represents lightgreen color on statistical charts +statisticsChartLineOrange: #f28c39; // represents orange color on statistical charts +statisticsChartLineIndigo: #7f79f3; // represents indigo color on statistical charts +statisticsChartLinePurple: #9f79e8; // represents purple color on statistical charts +statisticsChartLineCyan: #40d0ca; // represents cyan color on statistical charts + // kotatogram ktgTopBarBg: topBarBg; // Kotatogram: top bar background ktgTopBarNameFg: dialogsNameFg; // Kotatogram: top bar name text diff --git a/ui/delayed_activation.cpp b/ui/delayed_activation.cpp index fb1250a..2dc2ea4 100644 --- a/ui/delayed_activation.cpp +++ b/ui/delayed_activation.cpp @@ -7,32 +7,80 @@ #include "ui/delayed_activation.h" #include "ui/ui_utility.h" +#include "base/call_delayed.h" +#include "base/invoke_queued.h" +#include "base/platform/base_platform_info.h" + +#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION +#include "base/platform/linux/base_linux_xcb_utilities.h" +#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION #include +#include namespace Ui { namespace { -auto Paused = false; +constexpr auto kPreventTimeout = crl::time(100); + +bool Paused/* = false*/; +bool Attempted/* = false*/; auto Window = QPointer(); +bool Unpause(bool force = false) { + if (force || Attempted) { + Attempted = false; + Paused = false; + return true; + } + return false; +} + } // namespace +void ActivateWindow(not_null widget) { + const auto window = widget->window(); + window->raise(); + window->activateWindow(); + ActivateWindowDelayed(window); +} + void ActivateWindowDelayed(not_null widget) { if (Paused) { + Attempted = true; return; } else if (std::exchange(Window, widget.get())) { return; } - crl::on_main(Window, [=] { - if (const auto widget = base::take(Window)) { - if (const auto window = widget->window()) { - if (!window->isHidden()) { - window->raise(); - window->activateWindow(); - } - } +#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION + const auto focusAncestor = [&] { + const auto focusWidget = QApplication::focusWidget(); + if (!focusWidget || !widget->window()) { + return false; } + return widget->window()->isAncestorOf(focusWidget); + }(); +#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION + crl::on_main(Window, [=] { + const auto widget = base::take(Window); + if (!widget) { + return; + } + const auto window = widget->window(); + if (!window || window->isHidden()) { + return; + } + window->raise(); + window->activateWindow(); +#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION + if (::Platform::IsX11() && focusAncestor) { + xcb_set_input_focus( + base::Platform::XCB::GetConnectionFromQt(), + XCB_INPUT_FOCUS_PARENT, + window->winId(), + XCB_CURRENT_TIME); + } +#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION }); } @@ -40,7 +88,22 @@ void PreventDelayedActivation() { Window = nullptr; Paused = true; PostponeCall([] { - Paused = false; + if (Unpause()) { + return; + } + InvokeQueued(qApp, [] { + if (Unpause()) { + return; + } + crl::on_main([] { + if (Unpause()) { + return; + } + base::call_delayed(kPreventTimeout, [] { + Unpause(true); + }); + }); + }); }); } diff --git a/ui/delayed_activation.h b/ui/delayed_activation.h index 4fd1c74..ed6b4cc 100644 --- a/ui/delayed_activation.h +++ b/ui/delayed_activation.h @@ -8,6 +8,7 @@ namespace Ui { +void ActivateWindow(not_null widget); void ActivateWindowDelayed(not_null widget); void PreventDelayedActivation(); diff --git a/ui/dpr/dpr_icon.cpp b/ui/dpr/dpr_icon.cpp new file mode 100644 index 0000000..6515cd3 --- /dev/null +++ b/ui/dpr/dpr_icon.cpp @@ -0,0 +1,32 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/dpr/dpr_icon.h" + +namespace dpr { + +QImage IconFrame( + const style::icon &icon, + const QColor &color, + double ratio) { + const auto scale = style::Scale() * ratio; + const auto use = (scale > 200. || style::DevicePixelRatio() > 2) + ? (300 / style::DevicePixelRatio()) + : (scale > 100.) + ? (200 / style::DevicePixelRatio()) + : (100 / style::DevicePixelRatio()); + auto image = icon.instance(color, use); + image.setDevicePixelRatio(1.); + const auto desired = icon.size() * ratio; + return (image.size() == desired) + ? image + : image.scaled( + desired, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); +} + +} // namespace dpr diff --git a/ui/dpr/dpr_icon.h b/ui/dpr/dpr_icon.h new file mode 100644 index 0000000..4b37793 --- /dev/null +++ b/ui/dpr/dpr_icon.h @@ -0,0 +1,20 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +#include "ui/style/style_core.h" + +class QImage; + +namespace dpr { + +[[nodiscard]] QImage IconFrame( + const style::icon &icon, + const QColor &color, + double ratio); + +} // namespace dpr diff --git a/ui/dpr/dpr_image.h b/ui/dpr/dpr_image.h new file mode 100644 index 0000000..34efd5f --- /dev/null +++ b/ui/dpr/dpr_image.h @@ -0,0 +1,50 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +#include + +#include +#include + +namespace dpr { + +// Validate(_cache, devicePixelRatioF(), size, [&](QPainter &p, QSize size) { +// ... paint using p ... +// }, (_cacheKey != cacheKey()), Qt::transparent); + +template +void Validate( + QImage &image, + double ratio, + QSize size, + Generator &&generator, + bool force, + std::optional fill = {}, + bool setResultRatio = true) { + size *= ratio; + const auto sizeChanged = (image.size() != size); + if (sizeChanged || force) { + if (sizeChanged) { + image = QImage(size, QImage::Format_ARGB32_Premultiplied); + } + if (fill) { + image.fill(*fill); + } + image.setDevicePixelRatio(1.); + auto p = QPainter(&image); + using namespace rpl::details; + if constexpr (is_callable_plain_v) { + generator(p, size); + } else { + generator(p); + } + } + image.setDevicePixelRatio(setResultRatio ? ratio : 1.); +} + +} // namespace dpr diff --git a/ui/dragging_scroll_manager.cpp b/ui/dragging_scroll_manager.cpp new file mode 100644 index 0000000..011b291 --- /dev/null +++ b/ui/dragging_scroll_manager.cpp @@ -0,0 +1,63 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/dragging_scroll_manager.h" + +#include "base/timer.h" + +namespace Ui { +namespace { + +// 37px per 15ms while select-by-drag. +inline constexpr auto kMaxScrollSpeed = 37; + +} // namespace + +DraggingScrollManager::DraggingScrollManager() = default; + +void DraggingScrollManager::scrollByTimer() { + const auto d = (_delta > 0) + ? std::min(_delta * 3 / 20 + 1, kMaxScrollSpeed) + : std::max(_delta * 3 / 20 - 1, -kMaxScrollSpeed); + _scrolls.fire_copy(d); +} + +void DraggingScrollManager::checkDeltaScroll(int delta) { + _delta = delta; + if (_delta) { + if (!_timer) { + _timer = std::make_unique([=] { scrollByTimer(); }); + } + _timer->callEach(15); + } else { + cancel(); + } +} + +void DraggingScrollManager::checkDeltaScroll( + const QPoint &point, + int top, + int bottom) { + const auto diff = point.y() - top; + checkDeltaScroll((diff < 0) + ? diff + : (point.y() >= bottom) + ? (point.y() - bottom + 1) + : 0); +} + +void DraggingScrollManager::cancel() { + if (_timer) { + _timer->cancel(); + _timer = nullptr; + } +} + +rpl::producer DraggingScrollManager::scrolls() const { + return _scrolls.events(); +} + +} // namespace Ui diff --git a/ui/dragging_scroll_manager.h b/ui/dragging_scroll_manager.h new file mode 100644 index 0000000..8503c2c --- /dev/null +++ b/ui/dragging_scroll_manager.h @@ -0,0 +1,34 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +namespace base { +class Timer; +} // namespace base + +namespace Ui { + +class DraggingScrollManager final { +public: + DraggingScrollManager(); + + void checkDeltaScroll(int delta); + void checkDeltaScroll(const QPoint &point, int top, int bottom); + void cancel(); + + [[nodiscard]] rpl::producer scrolls() const; + +private: + void scrollByTimer(); + + std::unique_ptr _timer; + int _delta = 0; + rpl::event_stream _scrolls; + +}; + +} // namespace Ui diff --git a/ui/dynamic_image.h b/ui/dynamic_image.h new file mode 100644 index 0000000..6c62830 --- /dev/null +++ b/ui/dynamic_image.h @@ -0,0 +1,19 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +namespace Ui { + +class DynamicImage { +public: + virtual ~DynamicImage() = default; + + [[nodiscard]] virtual QImage image(int size) = 0; + virtual void subscribeToUpdates(Fn callback) = 0; +}; + +} // namespace Ui diff --git a/ui/effects/animation_value.cpp b/ui/effects/animation_value.cpp index 3370a8f..c83c418 100644 --- a/ui/effects/animation_value.cpp +++ b/ui/effects/animation_value.cpp @@ -19,50 +19,113 @@ int SlowMultiplierMinusOne/* = 0*/; } // namespace transition linear = [](const float64 &delta, const float64 &dt) { - return delta * dt; + Expects(!std::isnan(delta)); + Expects(!std::isnan(dt)); + + const auto result = delta * dt; + + Ensures(!std::isnan(result)); + return result; }; transition sineInOut = [](const float64 &delta, const float64 &dt) { - return -(delta / 2) * (cos(M_PI * dt) - 1); + Expects(!std::isnan(delta)); + Expects(!std::isnan(dt)); + + const auto result = -(delta / 2) * (cos(M_PI * dt) - 1); + + Ensures(!std::isnan(result)); + return result; }; transition halfSine = [](const float64 &delta, const float64 &dt) { - return delta * sin(M_PI * dt / 2); + Expects(!std::isnan(delta)); + Expects(!std::isnan(dt)); + + const auto result = delta * sin(M_PI * dt / 2); + + Ensures(!std::isnan(result)); + return result; }; transition easeOutBack = [](const float64 &delta, const float64 &dt) { + Expects(!std::isnan(delta)); + Expects(!std::isnan(dt)); + static constexpr auto s = 1.70158; - const float64 t = dt - 1; - return delta * (t * t * ((s + 1) * t + s) + 1); + const auto t = dt - 1; + Assert(!std::isnan(t)); + const auto result = delta * (t * t * ((s + 1) * t + s) + 1); + + Ensures(!std::isnan(result)); + return result; }; transition easeInCirc = [](const float64 &delta, const float64 &dt) { - return -delta * (sqrt(1 - dt * dt) - 1); + Expects(!std::isnan(delta)); + Expects(!std::isnan(dt)); + + const auto result = -delta * (sqrt(1 - dt * dt) - 1); + + Ensures(!std::isnan(result)); + return result; }; transition easeOutCirc = [](const float64 &delta, const float64 &dt) { - const float64 t = dt - 1; - return delta * sqrt(1 - t * t); + Expects(!std::isnan(delta)); + Expects(!std::isnan(dt)); + + const auto t = dt - 1; + Assert(!std::isnan(t)); + const auto result = delta * sqrt(1 - t * t); + + Ensures(!std::isnan(result)); + return result; }; transition easeInCubic = [](const float64 &delta, const float64 &dt) { - return delta * dt * dt * dt; + const auto result = delta * dt * dt * dt; + + Ensures(!std::isnan(result)); + return result; }; transition easeOutCubic = [](const float64 &delta, const float64 &dt) { - const float64 t = dt - 1; - return delta * (t * t * t + 1); + Expects(!std::isnan(delta)); + Expects(!std::isnan(dt)); + + const auto t = dt - 1; + Assert(!std::isnan(t)); + const auto result = delta * (t * t * t + 1); + + Ensures(!std::isnan(result)); + return result; }; transition easeInQuint = [](const float64 &delta, const float64 &dt) { - const float64 t2 = dt * dt; - return delta * t2 * t2 * dt; + Expects(!std::isnan(delta)); + Expects(!std::isnan(dt)); + + const auto t2 = dt * dt; + Assert(!std::isnan(t2)); + const auto result = delta * t2 * t2 * dt; + + Ensures(!std::isnan(result)); + return result; }; transition easeOutQuint = [](const float64 &delta, const float64 &dt) { - const float64 t = dt - 1, t2 = t * t; - return delta * (t2 * t2 * t + 1); + Expects(!std::isnan(delta)); + Expects(!std::isnan(dt)); + + const auto t = dt - 1, t2 = t * t; + Assert(!std::isnan(t)); + Assert(!std::isnan(t2)); + const auto result = delta * (t2 * t2 * t + 1); + + Ensures(!std::isnan(result)); + return result; }; rpl::producer Disables() { @@ -90,7 +153,7 @@ void SetSlowMultiplier(int multiplier) { void DrawStaticLoading( QPainter &p, QRectF rect, - int stroke, + float64 stroke, QPen pen, QBrush brush) { PainterHighQualityEnabler hq(p); diff --git a/ui/effects/animation_value.h b/ui/effects/animation_value.h index 1b9694b..593432e 100644 --- a/ui/effects/animation_value.h +++ b/ui/effects/animation_value.h @@ -14,16 +14,21 @@ namespace anim { -enum class type { +enum class type : uchar { normal, instant, }; -enum class activation { +enum class activation : uchar { normal, background, }; +enum class repeat : uchar { + loop, + once, +}; + using transition = Fn; extern transition linear; @@ -94,12 +99,12 @@ private: }; -TG_FORCE_INLINE float64 interpolateF(int a, int b, float64 b_ratio) { +TG_FORCE_INLINE float64 interpolateToF(int a, int b, float64 b_ratio) { return a + float64(b - a) * b_ratio; } TG_FORCE_INLINE int interpolate(int a, int b, float64 b_ratio) { - return base::SafeRound(interpolateF(a, b, b_ratio)); + return base::SafeRound(interpolateToF(a, b, b_ratio)); } #ifdef ARCH_CPU_32_BITS @@ -317,6 +322,11 @@ TG_FORCE_INLINE QBrush brush(style::color a, style::color b, float64 b_ratio) { return (b_ratio > 0) ? ((b_ratio < 1) ? brush(a->c, b->c, b_ratio) : b) : a; } +TG_FORCE_INLINE QColor with_alpha(QColor color, float64 alpha) { + color.setAlphaF(color.alphaF() * alpha); + return color; +} + template QPainterPath interpolate(QPointF (&from)[N], QPointF (&to)[N], float64 k) { static_assert(N > 1, "Wrong points count in path!"); @@ -357,7 +367,7 @@ void SetSlowMultiplier(int multiplier); // 1 - default, 10 - slow x10. void DrawStaticLoading( QPainter &p, QRectF rect, - int stroke, + float64 stroke, QPen pen, QBrush brush = Qt::NoBrush); diff --git a/ui/effects/animation_value_f.h b/ui/effects/animation_value_f.h new file mode 100644 index 0000000..bd8adb7 --- /dev/null +++ b/ui/effects/animation_value_f.h @@ -0,0 +1,26 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +namespace anim { + +TG_FORCE_INLINE float64 interpolateF(float a, float b, float64 b_ratio) { + return a + float64(b - a) * b_ratio; +}; + +TG_FORCE_INLINE QRectF interpolatedRectF( + const QRectF &r1, + const QRectF &r2, + float64 ratio) { + return QRectF( + interpolateF(r1.x(), r2.x(), ratio), + interpolateF(r1.y(), r2.y(), ratio), + interpolateF(r1.width(), r2.width(), ratio), + interpolateF(r1.height(), r2.height(), ratio)); +} + +} // namespace anim diff --git a/ui/effects/animations.h b/ui/effects/animations.h index 57d52d3..a918cfc 100644 --- a/ui/effects/animations.h +++ b/ui/effects/animations.h @@ -10,6 +10,7 @@ #include #include +#include namespace Ui { namespace Animations { @@ -337,14 +338,24 @@ inline void Simple::start( that = _data.get(), callback = Prepare(std::forward(callback)) ](crl::time now) { + Assert(!std::isnan(double(now - that->animation.started()))); const auto time = anim::Disabled() ? that->duration : (now - that->animation.started()); + Assert(!std::isnan(time)); + Assert(!std::isnan(that->delta)); + Assert(!std::isnan(that->duration)); const auto finished = (time >= that->duration); + Assert(finished || that->duration > 0); + const auto progressRatio = finished ? 1. : time / that->duration; + Assert(!std::isnan(progressRatio)); const auto progress = finished ? that->delta - : that->transition(that->delta, time / that->duration); + : that->transition(that->delta, progressRatio); + Assert(!std::isnan(that->from)); + Assert(!std::isnan(progress)); that->value = that->from + progress; + Assert(!std::isnan(that->value)); if (finished) { that->animation.stop(); @@ -401,7 +412,12 @@ inline bool Simple::animating() const { } TG_FORCE_INLINE float64 Simple::value(float64 final) const { - return animating() ? _data->value : final; + if (animating()) { + Assert(!std::isnan(_data->value)); + return _data->value; + } + Assert(!std::isnan(final)); + return final; } inline void Simple::startPrepared( diff --git a/ui/effects/cross_animation.cpp b/ui/effects/cross_animation.cpp index 61084d7..18a9cd4 100644 --- a/ui/effects/cross_animation.cpp +++ b/ui/effects/cross_animation.cpp @@ -99,7 +99,7 @@ void transformLoadingCross(float64 loading, std::array &po } // namespace void CrossAnimation::paintStaticLoading( - Painter &p, + QPainter &p, const style::CrossAnimation &st, style::color color, int x, @@ -110,7 +110,7 @@ void CrossAnimation::paintStaticLoading( } void CrossAnimation::paint( - Painter &p, + QPainter &p, const style::CrossAnimation &st, style::color color, int x, @@ -120,14 +120,17 @@ void CrossAnimation::paint( float64 loading) { PainterHighQualityEnabler hq(p); - auto sqrt2 = sqrt(2.); - auto deleteScale = shown + st.minScale * (1. - shown); - auto deleteSkip = (deleteScale * st.skip) + (1. - deleteScale) * (st.size / 2); - auto deleteLeft = style::rtlpoint(x + deleteSkip, 0, outerWidth).x() + 0.; - auto deleteTop = y + deleteSkip + 0.; - auto deleteWidth = st.size - 2 * deleteSkip; - auto deleteHeight = st.size - 2 * deleteSkip; - auto deleteStroke = st.stroke / sqrt2; + const auto stroke = style::ConvertScaleExact(st.stroke); + + const auto deleteScale = shown + st.minScale * (1. - shown); + const auto deleteSkip = (deleteScale * st.skip) + + (1. - deleteScale) * (st.size / 2); + const auto deleteLeft = 0. + + style::rtlpoint(x + deleteSkip, 0, outerWidth).x(); + const auto deleteTop = y + deleteSkip + 0.; + const auto deleteWidth = st.size - 2 * deleteSkip; + const auto deleteHeight = st.size - 2 * deleteSkip; + const auto deleteStroke = stroke / M_SQRT2; std::array pathDelete = { { { deleteLeft, deleteTop + deleteStroke }, { deleteLeft + deleteStroke, deleteTop }, @@ -176,10 +179,10 @@ void CrossAnimation::paint( p.fillPath(path, color); } if (loadingArcLength != 0) { - auto roundSkip = (st.size * (1 - sqrt2) + 2 * sqrt2 * deleteSkip + st.stroke) / 2; + auto roundSkip = (st.size * (1 - M_SQRT2) + 2 * M_SQRT2 * deleteSkip + stroke) / 2; auto roundPart = QRectF(x + roundSkip, y + roundSkip, st.size - 2 * roundSkip, st.size - 2 * roundSkip); if (staticLoading) { - anim::DrawStaticLoading(p, roundPart, st.stroke, color); + anim::DrawStaticLoading(p, roundPart, stroke, color); } else { auto loadingArcStart = kFullArcLength / 8; if (shown < 1.) { @@ -192,7 +195,7 @@ void CrossAnimation::paint( p.setBrush(Qt::NoBrush); auto pen = color->p; - pen.setWidthF(st.stroke); + pen.setWidthF(stroke); pen.setCapStyle(Qt::RoundCap); p.setPen(pen); p.drawArc(roundPart, loadingArcStart, loadingArcLength); diff --git a/ui/effects/cross_animation.h b/ui/effects/cross_animation.h index ffa17bd..e0ca4c4 100644 --- a/ui/effects/cross_animation.h +++ b/ui/effects/cross_animation.h @@ -15,7 +15,7 @@ namespace Ui { class CrossAnimation { public: static void paint( - Painter &p, + QPainter &p, const style::CrossAnimation &st, style::color color, int x, @@ -24,7 +24,7 @@ public: float64 shown, float64 loading = 0.); static void paintStaticLoading( - Painter &p, + QPainter &p, const style::CrossAnimation &st, style::color color, int x, diff --git a/ui/effects/cross_line.cpp b/ui/effects/cross_line.cpp index c1e0f96..aeffdef 100644 --- a/ui/effects/cross_line.cpp +++ b/ui/effects/cross_line.cpp @@ -36,7 +36,7 @@ CrossLineAnimation::CrossLineAnimation( } void CrossLineAnimation::paint( - Painter &p, + QPainter &p, QPoint position, float64 progress, std::optional colorOverride) { @@ -44,7 +44,7 @@ void CrossLineAnimation::paint( } void CrossLineAnimation::paint( - Painter &p, + QPainter &p, int left, int top, float64 progress, @@ -86,7 +86,7 @@ void CrossLineAnimation::fillFrame( topLine.setLength(topLine.length() * progress); auto bottomLine = topLine.translated(0, _strokePen.widthF() + 1); - Painter q(&_frame); + auto q = QPainter(&_frame); PainterHighQualityEnabler hq(q); const auto colorize = ((colorOverride && colorOverride->alpha() != 255) || (!colorOverride && _st.fg->c.alpha() != 255)); diff --git a/ui/effects/cross_line.h b/ui/effects/cross_line.h index f8a27ea..99fc506 100644 --- a/ui/effects/cross_line.h +++ b/ui/effects/cross_line.h @@ -8,8 +8,6 @@ #include "styles/style_widgets.h" -class Painter; - namespace Ui { class CrossLineAnimation { @@ -20,12 +18,12 @@ public: float angle = 315); void paint( - Painter &p, + QPainter &p, QPoint position, float64 progress, std::optional colorOverride = std::nullopt); void paint( - Painter &p, + QPainter &p, int left, int top, float64 progress, diff --git a/ui/effects/frame_generator.cpp b/ui/effects/frame_generator.cpp new file mode 100644 index 0000000..a50b443 --- /dev/null +++ b/ui/effects/frame_generator.cpp @@ -0,0 +1,79 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/effects/frame_generator.h" + +#include "ui/image/image_prepare.h" + +namespace Ui { + +ImageFrameGenerator::ImageFrameGenerator(const QByteArray &bytes) +: _bytes(bytes) { +} + +ImageFrameGenerator::ImageFrameGenerator(const QImage &image) +: _image(image) { +} + +int ImageFrameGenerator::count() { + return 1; +} + +double ImageFrameGenerator::rate() { + return 1.; +} + +FrameGenerator::Frame ImageFrameGenerator::renderNext( + QImage storage, + QSize size, + Qt::AspectRatioMode mode) { + return renderCurrent(std::move(storage), size, mode); +} + +FrameGenerator::Frame ImageFrameGenerator::renderCurrent( + QImage storage, + QSize size, + Qt::AspectRatioMode mode) { + if (_image.isNull() && !_bytes.isEmpty()) { + _image = Images::Read({ + .content = _bytes, + }).image; + _bytes = QByteArray(); + } + if (_image.isNull()) { + return {}; + } + auto scaled = _image.scaled( + size, + mode, + Qt::SmoothTransformation + ).convertToFormat(QImage::Format_ARGB32_Premultiplied); + if (scaled.size() == size) { + return { .image = std::move(scaled) }; + } + auto result = QImage(size, QImage::Format_ARGB32_Premultiplied); + result.fill(Qt::transparent); + + const auto skipx = (size.width() - scaled.width()) / 2; + const auto skipy = (size.height() - scaled.height()) / 2; + const auto srcPerLine = scaled.bytesPerLine(); + const auto dstPerLine = result.bytesPerLine(); + const auto lineBytes = scaled.width() * 4; + auto src = scaled.constBits(); + auto dst = result.bits() + (skipx * 4) + (skipy * srcPerLine); + for (auto y = 0, height = scaled.height(); y != height; ++y) { + memcpy(dst, src, lineBytes); + src += srcPerLine; + dst += dstPerLine; + } + + return { .image = std::move(result), .last = true }; +} + +void ImageFrameGenerator::jumpToStart() { +} + +} // namespace Ui diff --git a/ui/effects/frame_generator.h b/ui/effects/frame_generator.h new file mode 100644 index 0000000..7c6a45f --- /dev/null +++ b/ui/effects/frame_generator.h @@ -0,0 +1,69 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +#include + +#include + +namespace Ui { + +class FrameGenerator { +public: + virtual ~FrameGenerator() = default; + + // 0 means unknown. + [[nodiscard]] virtual int count() = 0; + + // 0. means unknown. + [[nodiscard]] virtual double rate() = 0; + + struct Frame { + crl::time duration = 0; + QImage image; + bool last = false; + }; + [[nodiscard]] virtual Frame renderNext( + QImage storage, + QSize size, + Qt::AspectRatioMode mode = Qt::IgnoreAspectRatio) = 0; + [[nodiscard]] virtual Frame renderCurrent( + QImage storage, + QSize size, + Qt::AspectRatioMode mode = Qt::IgnoreAspectRatio) = 0; + + virtual void jumpToStart() = 0; + +}; + +class ImageFrameGenerator final : public Ui::FrameGenerator { +public: + explicit ImageFrameGenerator(const QByteArray &bytes); + explicit ImageFrameGenerator(const QImage &image); + + int count() override; + double rate() override; + Frame renderNext( + QImage storage, + QSize size, + Qt::AspectRatioMode mode = Qt::IgnoreAspectRatio) override; + Frame renderCurrent( + QImage storage, + QSize size, + Qt::AspectRatioMode mode = Qt::IgnoreAspectRatio) override; + void jumpToStart() override; + +private: + QByteArray _bytes; + QImage _image; + +}; + +[[nodiscard]] bool GoodStorageForFrame(const QImage &storage, QSize size); +[[nodiscard]] QImage CreateFrameStorage(QSize size); + +} // namespace Ui diff --git a/ui/effects/gradient.cpp b/ui/effects/gradient.cpp new file mode 100644 index 0000000..4a99d32 --- /dev/null +++ b/ui/effects/gradient.cpp @@ -0,0 +1,30 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/effects/gradient.h" + +namespace anim { + +QColor gradient_color_at(const QGradientStops & stops, float64 ratio) { + for (auto i = 1; i < stops.size(); i++) { + const auto currentPoint = stops[i].first; + const auto previousPoint = stops[i - 1].first; + + if ((ratio <= currentPoint) && (ratio >= previousPoint)) { + return anim::color( + stops[i - 1].second, + stops[i].second, + (ratio - previousPoint) / (currentPoint - previousPoint)); + } + } + return QColor(); +} + +QColor gradient_color_at(const QGradient &gradient, float64 ratio) { + return gradient_color_at(gradient.stops(), ratio); +} + +} // namespace anim diff --git a/ui/effects/gradient.h b/ui/effects/gradient.h index 1c882f0..732492c 100644 --- a/ui/effects/gradient.h +++ b/ui/effects/gradient.h @@ -14,6 +14,14 @@ namespace anim { +[[nodiscard]] QColor gradient_color_at( + const QGradientStops &stops, + float64 ratio); + +[[nodiscard]] QColor gradient_color_at( + const QGradient &gradient, + float64 ratio); + struct gradient_colors { explicit gradient_colors(QColor color) { stops.push_back({ 0., color }); diff --git a/ui/effects/numbers_animation.cpp b/ui/effects/numbers_animation.cpp index 6f81a75..e71b260 100644 --- a/ui/effects/numbers_animation.cpp +++ b/ui/effects/numbers_animation.cpp @@ -17,12 +17,21 @@ NumbersAnimation::NumbersAnimation( const style::font &font, Fn animationCallback) : _font(font) +, _duration(st::slideWrapDuration) , _animationCallback(std::move(animationCallback)) { for (auto ch = '0'; ch != '9'; ++ch) { - accumulate_max(_digitWidth, _font->m.horizontalAdvance(ch)); + accumulate_max(_digitWidth, _font->width(ch)); } } +void NumbersAnimation::setDuration(int duration) { + _duration = duration; +} + +void NumbersAnimation::setDisabledMonospace(bool value) { + _disabledMonospace = value; +} + void NumbersAnimation::setText(const QString &text, int value) { if (_a_ready.animating()) { _delayedText = text; @@ -67,7 +76,7 @@ void NumbersAnimation::realSetText(QString text, int value) { digit.from = digit.to; digit.fromWidth = digit.toWidth; digit.to = (newSize + i < size) ? QChar(0) : text[newSize + i - size]; - digit.toWidth = digit.to.unicode() ? _font->m.horizontalAdvance(digit.to) : 0; + digit.toWidth = digit.to.unicode() ? _font->width(digit.to) : 0; if (digit.from != digit.to) { animating = true; } @@ -75,14 +84,19 @@ void NumbersAnimation::realSetText(QString text, int value) { --oldSize; } } - _fromWidth = oldSize * _digitWidth; - _toWidth = newSize * _digitWidth; + if (_disabledMonospace) { + _fromWidth = _toWidth; + _toWidth = _font->width(text); + } else { + _fromWidth = oldSize * _digitWidth; + _toWidth = newSize * _digitWidth; + } if (animating) { _a_ready.start( [this] { animationCallback(); }, 0., 1., - st::slideWrapDuration); + _duration); } } @@ -117,30 +131,37 @@ void NumbersAnimation::paint(QPainter &p, int x, int y, int outerWidth) { QString singleChar('0'); if (style::RightToLeft()) x = outerWidth - x - width; - x += width - _digits.size() * _digitWidth; + x += width + - (_disabledMonospace ? _toWidth : _digits.size() * _digitWidth); auto fromTop = anim::interpolate(0, _font->height, progress) * (_growing ? 1 : -1); auto toTop = anim::interpolate(_font->height, 0, progress) * (_growing ? -1 : 1); for (auto i = 0; i != digitsCount; ++i) { auto &digit = _digits[i]; auto from = digit.from; auto to = digit.to; + const auto toCharWidth = (!_disabledMonospace || to.isDigit()) + ? _digitWidth + : _font->width(to); + const auto fromCharWidth = (!_disabledMonospace || from.isDigit()) + ? _digitWidth + : _font->width(from); if (from == to) { p.setOpacity(1.); singleChar[0] = from; - p.drawText(x + (_digitWidth - digit.fromWidth) / 2, y + _font->ascent, singleChar); + p.drawText(x + (toCharWidth - digit.fromWidth) / 2, y + _font->ascent, singleChar); } else { if (from.unicode()) { p.setOpacity(1. - progress); singleChar[0] = from; - p.drawText(x + (_digitWidth - digit.fromWidth) / 2, y + fromTop + _font->ascent, singleChar); + p.drawText(x + (fromCharWidth - digit.fromWidth) / 2, y + fromTop + _font->ascent, singleChar); } if (to.unicode()) { p.setOpacity(progress); singleChar[0] = to; - p.drawText(x + (_digitWidth - digit.toWidth) / 2, y + toTop + _font->ascent, singleChar); + p.drawText(x + (toCharWidth - digit.toWidth) / 2, y + toTop + _font->ascent, singleChar); } } - x += _digitWidth; + x += std::max(toCharWidth, fromCharWidth); } p.setOpacity(1.); } diff --git a/ui/effects/numbers_animation.h b/ui/effects/numbers_animation.h index 49aac7e..b18d217 100644 --- a/ui/effects/numbers_animation.h +++ b/ui/effects/numbers_animation.h @@ -25,6 +25,8 @@ public: _widthChangedCallback = std::move(callback); } void setText(const QString &text, int value); + void setDuration(int duration); + void setDisabledMonospace(bool value); void finishAnimating(); void paint(QPainter &p, int x, int y, int outerWidth); @@ -44,6 +46,8 @@ private: const style::font &_font; + int _duration; + QList _digits; int _digitWidth = 0; @@ -57,6 +61,8 @@ private: int _value = 0; bool _growing = false; + bool _disabledMonospace = false; + Fn _animationCallback; Fn _widthChangedCallback; diff --git a/ui/effects/panel_animation.cpp b/ui/effects/panel_animation.cpp index 9109599..51144b5 100644 --- a/ui/effects/panel_animation.cpp +++ b/ui/effects/panel_animation.cpp @@ -361,30 +361,59 @@ void PanelAnimation::start() { checkCorner(_bottomRight); } -void PanelAnimation::paintFrame(QPainter &p, int x, int y, int outerWidth, float64 dt, float64 opacity) { +auto PanelAnimation::computeState(float64 dt, float64 opacity) const +-> PaintState { + auto &transition = anim::easeOutCirc; + if (dt < _alphaDuration) { + opacity *= transition(1., dt / _alphaDuration); + } + const auto widthProgress = (_startWidth < 0 || dt >= _widthDuration) + ? 1. + : transition(1., dt / _widthDuration); + const auto heightProgress = (_startHeight < 0 || dt >= _heightDuration) + ? 1. + : transition(1., dt / _heightDuration); + const auto frameWidth = (widthProgress < 1.) + ? anim::interpolate(_startWidth, _finalInnerWidth, widthProgress) + : _finalInnerWidth; + const auto frameHeight = (heightProgress < 1.) + ? anim::interpolate(_startHeight, _finalInnerHeight, heightProgress) + : _finalInnerHeight; + const auto ratio = style::DevicePixelRatio(); + return { + .opacity = opacity, + .widthProgress = widthProgress, + .heightProgress = heightProgress, + .fade = transition(1., dt), + .width = frameWidth / ratio, + .height = frameHeight / ratio, + }; +} + +auto PanelAnimation::paintFrame( + QPainter &p, + int x, + int y, + int outerWidth, + float64 dt, + float64 opacity) +-> PaintState { Assert(started()); Assert(dt >= 0.); const auto pixelRatio = style::DevicePixelRatio(); - auto &transition = anim::easeOutCirc; - if (dt < _alphaDuration) opacity *= transition(1., dt / _alphaDuration); + const auto state = computeState(dt, opacity); + opacity = state.opacity; _frameAlpha = anim::interpolate(1, 256, opacity); - - auto frameWidth = (_startWidth < 0 || dt >= _widthDuration) ? _finalInnerWidth : anim::interpolate(_startWidth, _finalInnerWidth, transition(1., dt / _widthDuration)); - auto frameHeight = (_startHeight < 0 || dt >= _heightDuration) ? _finalInnerHeight : anim::interpolate(_startHeight, _finalInnerHeight, transition(1., dt / _heightDuration)); - if (auto decrease = (frameWidth % pixelRatio)) { - frameWidth -= decrease; - } - if (auto decrease = (frameHeight % pixelRatio)) { - frameHeight -= decrease; - } + const auto frameWidth = state.width * pixelRatio; + const auto frameHeight = state.height * pixelRatio; auto frameLeft = (_origin == Origin::TopLeft || _origin == Origin::BottomLeft) ? _finalInnerLeft : (_finalInnerRight - frameWidth); auto frameTop = (_origin == Origin::TopLeft || _origin == Origin::TopRight) ? _finalInnerTop : (_finalInnerBottom - frameHeight); auto frameRight = frameLeft + frameWidth; auto frameBottom = frameTop + frameHeight; - auto fadeTop = (_fadeHeight > 0) ? std::clamp(anim::interpolate(_startFadeTop, _finalInnerHeight, transition(1., dt)), 0, frameHeight) : frameHeight; + auto fadeTop = (_fadeHeight > 0) ? std::clamp(anim::interpolate(_startFadeTop, _finalInnerHeight, state.fade), 0, frameHeight) : frameHeight; if (auto decrease = (fadeTop % pixelRatio)) { fadeTop -= decrease; } @@ -503,6 +532,8 @@ void PanelAnimation::paintFrame(QPainter &p, int x, int y, int outerWidth, float //} p.drawImage(style::rtlpoint(x + (outerLeft / pixelRatio), y + (outerTop / pixelRatio), outerWidth), _frame, QRect(outerLeft, outerTop, outerRight - outerLeft, outerBottom - outerTop)); + + return state; } } // namespace Ui diff --git a/ui/effects/panel_animation.h b/ui/effects/panel_animation.h index 0f6844d..e114eb9 100644 --- a/ui/effects/panel_animation.h +++ b/ui/effects/panel_animation.h @@ -79,11 +79,27 @@ public: PanelAnimation(const style::PanelAnimation &st, Origin origin) : _st(st), _origin(origin) { } + struct PaintState { + float64 opacity = 0.; + float64 widthProgress = 0.; + float64 heightProgress = 0.; + float64 fade = 0.; + int width = 0; + int height = 0; + }; + void setFinalImage(QImage &&finalImage, QRect inner); void setSkipShadow(bool skipShadow); void start(); - void paintFrame(QPainter &p, int x, int y, int outerWidth, float64 dt, float64 opacity); + [[nodiscard]] PaintState computeState(float64 dt, float64 opacity) const; + PaintState paintFrame( + QPainter &p, + int x, + int y, + int outerWidth, + float64 dt, + float64 opacity); private: void setStartWidth(); diff --git a/ui/effects/radial_animation.cpp b/ui/effects/radial_animation.cpp index ffea2ac..2ae1d53 100644 --- a/ui/effects/radial_animation.cpp +++ b/ui/effects/radial_animation.cpp @@ -112,13 +112,25 @@ RadialState RadialAnimation::computeState() const { return { _opacity, from, length }; } +void InfiniteRadialAnimation::init() { + anim::Disables() | rpl::filter([=] { + return animating(); + }) | rpl::start_with_next([=](bool disabled) { + if (!disabled && !_animation.animating()) { + _animation.start(); + } else if (disabled && _animation.animating()) { + _animation.stop(); + } + }, _lifetime); +} + void InfiniteRadialAnimation::start(crl::time skip) { - const auto now = crl::now(); - if (_workFinished <= now && (_workFinished || !_workStarted)) { + if (!animating()) { + const auto now = crl::now(); _workStarted = std::max(now + _st.sineDuration - skip, crl::time(1)); _workFinished = 0; } - if (!_animation.animating()) { + if (!anim::Disabled() && !_animation.animating()) { _animation.start(); } } @@ -213,7 +225,7 @@ RadialState InfiniteRadialAnimation::computeState() { const auto now = crl::now(); const auto linear = kFullArcLength - int(((now * kFullArcLength) / _st.linearPeriod) % kFullArcLength); - if (!_workStarted || (_workFinished && _workFinished <= now)) { + if (!animating()) { const auto shown = 0.; _animation.stop(); return { diff --git a/ui/effects/radial_animation.h b/ui/effects/radial_animation.h index 984e49a..1ed035d 100644 --- a/ui/effects/radial_animation.h +++ b/ui/effects/radial_animation.h @@ -73,7 +73,7 @@ public: const style::InfiniteRadialAnimation &st); [[nodiscard]] bool animating() const { - return _animation.animating(); + return _workStarted && (!_workFinished || _workFinished > crl::now()); } void start(crl::time skip = 0); @@ -101,10 +101,13 @@ public: [[nodiscard]] RadialState computeState(); private: + void init(); + const style::InfiniteRadialAnimation &_st; crl::time _workStarted = 0; crl::time _workFinished = 0; Ui::Animations::Basic _animation; + rpl::lifetime _lifetime; }; @@ -114,6 +117,7 @@ inline InfiniteRadialAnimation::InfiniteRadialAnimation( const style::InfiniteRadialAnimation &st) : _st(st) , _animation(std::forward(callback)) { + init(); } } // namespace Ui diff --git a/ui/effects/ripple_animation.cpp b/ui/effects/ripple_animation.cpp index 5fbb030..3971cc7 100644 --- a/ui/effects/ripple_animation.cpp +++ b/ui/effects/ripple_animation.cpp @@ -9,15 +9,28 @@ #include "ui/effects/animations.h" #include "ui/painter.h" #include "ui/ui_utility.h" +#include "ui/image/image_prepare.h" +#include "styles/style_widgets.h" namespace Ui { class RippleAnimation::Ripple { public: - Ripple(const style::RippleAnimation &st, QPoint origin, int startRadius, const QPixmap &mask, Fn update); - Ripple(const style::RippleAnimation &st, const QPixmap &mask, Fn update); + Ripple( + const style::RippleAnimation &st, + QPoint origin, + int startRadius, + const QPixmap &mask, + Fn update); + Ripple( + const style::RippleAnimation &st, + const QPixmap &mask, + Fn update); - void paint(QPainter &p, const QPixmap &mask, const QColor *colorOverride); + void paint( + QPainter &p, + const QPixmap &mask, + const QColor *colorOverride); void stop(); void unstop(); @@ -43,7 +56,12 @@ private: }; -RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, QPoint origin, int startRadius, const QPixmap &mask, Fn update) +RippleAnimation::Ripple::Ripple( + const style::RippleAnimation &st, + QPoint origin, + int startRadius, + const QPixmap &mask, + Fn update) : _st(st) , _update(update) , _origin(origin) @@ -59,7 +77,9 @@ RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, QPoint origin, { 0, _frame.height() / pixelRatio }, }; for (auto point : points) { - accumulate_max(_radiusTo, style::point::dotProduct(_origin - point, _origin - point)); + accumulate_max( + _radiusTo, + style::point::dotProduct(_origin - point, _origin - point)); } _radiusTo = qRound(sqrt(_radiusTo)); @@ -79,7 +99,10 @@ RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, const QPixmap _hide.start(_update, 0., 1., _st.hideDuration); } -void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, const QColor *colorOverride) { +void RippleAnimation::Ripple::paint( + QPainter &p, + const QPixmap &mask, + const QColor *colorOverride) { auto opacity = _hide.value(_hiding ? 0. : 1.); if (opacity == 0.) { return; @@ -92,9 +115,11 @@ void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, const QCol Assert(!std::isnan(diff)); const auto mult = diff * shown; Assert(!std::isnan(mult)); - const auto interpolated = _radiusFrom + mult;//anim::interpolateF(_radiusFrom, _radiusTo, shown); + const auto interpolated = _radiusFrom + mult; + //anim::interpolateF(_radiusFrom, _radiusTo, shown); Assert(!std::isnan(interpolated)); - auto radius = int(base::SafeRound(interpolated));//anim::interpolate(_radiusFrom, _radiusTo, _show.value(1.)); + auto radius = int(base::SafeRound(interpolated)); + //anim::interpolate(_radiusFrom, _radiusTo, _show.value(1.)); _frame.fill(Qt::transparent); { QPainter p(&_frame); @@ -151,7 +176,10 @@ void RippleAnimation::Ripple::clearCache() { _cache = QPixmap(); } -RippleAnimation::RippleAnimation(const style::RippleAnimation &st, QImage mask, Fn callback) +RippleAnimation::RippleAnimation( + const style::RippleAnimation &st, + QImage mask, + Fn callback) : _st(st) , _mask(PixmapFromImage(std::move(mask))) , _update(callback) { @@ -160,7 +188,8 @@ RippleAnimation::RippleAnimation(const style::RippleAnimation &st, QImage mask, void RippleAnimation::add(QPoint origin, int startRadius) { lastStop(); - _ripples.push_back(std::make_unique(_st, origin, startRadius, _mask, _update)); + _ripples.push_back( + std::make_unique(_st, origin, startRadius, _mask, _update)); } void RippleAnimation::addFading() { @@ -195,7 +224,12 @@ void RippleAnimation::forceRepaint() { } } -void RippleAnimation::paint(QPainter &p, int x, int y, int outerWidth, const QColor *colorOverride) { +void RippleAnimation::paint( + QPainter &p, + int x, + int y, + int outerWidth, + const QColor *colorOverride) { if (_ripples.empty()) { return; } @@ -211,8 +245,13 @@ void RippleAnimation::paint(QPainter &p, int x, int y, int outerWidth, const QCo clearFinished(); } -QImage RippleAnimation::maskByDrawer(QSize size, bool filled, Fn drawer) { - auto result = QImage(size * style::DevicePixelRatio(), QImage::Format_ARGB32_Premultiplied); +QImage RippleAnimation::MaskByDrawer( + QSize size, + bool filled, + Fn drawer) { + auto result = QImage( + size * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(style::DevicePixelRatio()); result.fill(filled ? QColor(255, 255, 255) : Qt::transparent); if (drawer) { @@ -226,18 +265,46 @@ QImage RippleAnimation::maskByDrawer(QSize size, bool filled, Fn()); +QImage RippleAnimation::RectMask(QSize size) { + return MaskByDrawer(size, true, nullptr); } -QImage RippleAnimation::roundRectMask(QSize size, int radius) { - return maskByDrawer(size, false, [size, radius](QPainter &p) { +QImage RippleAnimation::RoundRectMask(QSize size, int radius) { + return MaskByDrawer(size, false, [&](QPainter &p) { p.drawRoundedRect(0, 0, size.width(), size.height(), radius, radius); }); } -QImage RippleAnimation::ellipseMask(QSize size) { - return maskByDrawer(size, false, [size](QPainter &p) { +QImage RippleAnimation::RoundRectMask( + QSize size, + Images::CornersMaskRef corners) { + return MaskByDrawer(size, true, [&](QPainter &p) { + p.setCompositionMode(QPainter::CompositionMode_Source); + const auto ratio = style::DevicePixelRatio(); + const auto corner = [&](int index, bool right, bool bottom) { + if (const auto image = corners.p[index]) { + if (!image->isNull()) { + const auto width = image->width() / ratio; + const auto height = image->height() / ratio; + p.drawImage( + QRect( + right ? (size.width() - width) : 0, + bottom ? (size.height() - height) : 0, + width, + height), + *image); + } + } + }; + corner(0, false, false); + corner(1, true, false); + corner(2, false, true); + corner(3, true, true); + }); +} + +QImage RippleAnimation::EllipseMask(QSize size) { + return MaskByDrawer(size, false, [&](QPainter &p) { p.drawEllipse(0, 0, size.width(), size.height()); }); } diff --git a/ui/effects/ripple_animation.h b/ui/effects/ripple_animation.h index 1ab6a89..47ceb0f 100644 --- a/ui/effects/ripple_animation.h +++ b/ui/effects/ripple_animation.h @@ -6,16 +6,26 @@ // #pragma once -#include "styles/style_widgets.h" - #include +namespace Images { +struct CornersMaskRef; +} // namespace Images + +namespace style { +struct RippleAnimation; +} // namespace style + namespace Ui { class RippleAnimation { public: - // White upon transparent mask, like colorizeImage(black-white-mask, white). - RippleAnimation(const style::RippleAnimation &st, QImage mask, Fn update); + // White upon transparent mask, + // like colorizeImage(black-white-mask, white). + RippleAnimation( + const style::RippleAnimation &st, + QImage mask, + Fn update); void add(QPoint origin, int startRadius = 0); void addFading(); @@ -24,16 +34,25 @@ public: void lastFinish(); void forceRepaint(); - void paint(QPainter &p, int x, int y, int outerWidth, const QColor *colorOverride = nullptr); + void paint( + QPainter &p, + int x, + int y, + int outerWidth, + const QColor *colorOverride = nullptr); bool empty() const { return _ripples.empty(); } - static QImage maskByDrawer(QSize size, bool filled, Fn drawer); - static QImage rectMask(QSize size); - static QImage roundRectMask(QSize size, int radius); - static QImage ellipseMask(QSize size); + static QImage MaskByDrawer( + QSize size, + bool filled, + Fn drawer); + static QImage RectMask(QSize size); + static QImage RoundRectMask(QSize size, int radius); + static QImage RoundRectMask(QSize size, Images::CornersMaskRef corners); + static QImage EllipseMask(QSize size); ~RippleAnimation(); diff --git a/ui/effects/round_area_with_shadow.cpp b/ui/effects/round_area_with_shadow.cpp new file mode 100644 index 0000000..f1bf71a --- /dev/null +++ b/ui/effects/round_area_with_shadow.cpp @@ -0,0 +1,471 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/effects/round_area_with_shadow.h" + +#include "ui/style/style_core.h" +#include "ui/image/image_prepare.h" +#include "ui/painter.h" + +namespace Ui { +namespace { + +constexpr auto kBgCacheIndex = 0; +constexpr auto kShadowCacheIndex = 0; +constexpr auto kOverlayMaskCacheIndex = 0; +constexpr auto kOverlayShadowCacheIndex = 1; +constexpr auto kOverlayCacheColumsCount = 2; +constexpr auto kDivider = 4; + +} // namespace + +[[nodiscard]] QImage RoundAreaWithShadow::PrepareImage(QSize size) { + const auto ratio = style::DevicePixelRatio(); + auto result = QImage( + size * ratio, + QImage::Format_ARGB32_Premultiplied); + result.setDevicePixelRatio(ratio); + return result; +} + +[[nodiscard]] QImage RoundAreaWithShadow::PrepareFramesCache( + QSize frame, + int columns) { + static_assert(!(kFramesCount % kDivider)); + + return PrepareImage(QSize( + frame.width() * kDivider * columns, + frame.height() * kFramesCount / kDivider)); +} + +[[nodiscard]] QRect RoundAreaWithShadow::FrameCacheRect( + int frameIndex, + int column, + QSize frame) { + const auto ratio = style::DevicePixelRatio(); + const auto origin = QPoint( + frame.width() * (kDivider * column + (frameIndex % kDivider)), + frame.height() * (frameIndex / kDivider)); + return QRect(ratio * origin, ratio * frame); +} + +RoundAreaWithShadow::RoundAreaWithShadow( + QSize inner, + QMargins shadow, + int twiceRadiusMax) +: _inner({}, inner) +, _outer(_inner.marginsAdded(shadow).size()) +, _overlay(QRect( + 0, + 0, + std::max(inner.width(), twiceRadiusMax), + std::max(inner.height(), twiceRadiusMax)).marginsAdded(shadow).size()) +, _cacheBg(PrepareFramesCache(_outer)) +, _shadowParts(PrepareFramesCache(_outer)) +, _overlayCacheParts(PrepareFramesCache(_overlay, kOverlayCacheColumsCount)) +, _overlayMaskScaled(PrepareImage(_overlay)) +, _overlayShadowScaled(PrepareImage(_overlay)) +, _shadowBuffer(PrepareImage(_outer)) { + _inner.translate(QRect({}, _outer).center() - _inner.center()); +} + +ImageSubrect RoundAreaWithShadow::validateOverlayMask( + int frameIndex, + QSize innerSize, + float64 radius, + int twiceRadius, + float64 scale) { + const auto ratio = style::DevicePixelRatio(); + const auto cached = (scale == 1.); + const auto full = cached + ? FrameCacheRect(frameIndex, kOverlayMaskCacheIndex, _overlay) + : QRect(QPoint(), _overlay * ratio); + + const auto minWidth = twiceRadius + _outer.width() - _inner.width(); + const auto minHeight = twiceRadius + _outer.height() - _inner.height(); + const auto maskSize = QSize( + std::max(_outer.width(), minWidth), + std::max(_outer.height(), minHeight)); + + const auto result = ImageSubrect{ + cached ? &_overlayCacheParts : &_overlayMaskScaled, + QRect(full.topLeft(), maskSize * ratio), + }; + if (cached && _validOverlayMask[frameIndex]) { + return result; + } + + auto p = QPainter(result.image.get()); + const auto position = full.topLeft() / ratio; + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(QRect(position, maskSize), Qt::transparent); + + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + auto hq = PainterHighQualityEnabler(p); + const auto inner = QRect(position + _inner.topLeft(), innerSize); + p.setPen(Qt::NoPen); + p.setBrush(Qt::white); + if (scale != 1.) { + const auto center = inner.center(); + p.save(); + p.translate(center); + p.scale(scale, scale); + p.translate(-center); + } + p.drawRoundedRect(inner, radius, radius); + if (scale != 1.) { + p.restore(); + } + + if (cached) { + _validOverlayMask[frameIndex] = true; + } + return result; +} + +ImageSubrect RoundAreaWithShadow::validateOverlayShadow( + int frameIndex, + QSize innerSize, + float64 radius, + int twiceRadius, + float64 scale, + const ImageSubrect &mask) { + const auto ratio = style::DevicePixelRatio(); + const auto cached = (scale == 1.); + const auto full = cached + ? FrameCacheRect(frameIndex, kOverlayShadowCacheIndex, _overlay) + : QRect(QPoint(), _overlay * ratio); + + const auto minWidth = twiceRadius + _outer.width() - _inner.width(); + const auto minHeight = twiceRadius + _outer.height() - _inner.height(); + const auto maskSize = QSize( + std::max(_outer.width(), minWidth), + std::max(_outer.height(), minHeight)); + + const auto result = ImageSubrect{ + cached ? &_overlayCacheParts : &_overlayShadowScaled, + QRect(full.topLeft(), maskSize * ratio), + }; + if (cached && _validOverlayShadow[frameIndex]) { + return result; + } + + const auto position = full.topLeft() / ratio; + + _overlayShadowScaled.fill(Qt::transparent); + const auto inner = QRect(_inner.topLeft(), innerSize); + const auto add = style::ConvertScale(2.5); + const auto shift = style::ConvertScale(0.5); + const auto extended = QRectF(inner).marginsAdded({ add, add, add, add }); + { + auto p = QPainter(&_overlayShadowScaled); + p.setCompositionMode(QPainter::CompositionMode_Source); + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(_shadow); + if (scale != 1.) { + const auto center = inner.center(); + p.translate(center); + p.scale(scale, scale); + p.translate(-center); + } + p.drawRoundedRect(extended.translated(0, shift), radius, radius); + p.end(); + } + + _overlayShadowScaled = Images::Blur(std::move(_overlayShadowScaled)); + + auto q = Painter(result.image); + if (result.image != &_overlayShadowScaled) { + q.setCompositionMode(QPainter::CompositionMode_Source); + q.drawImage( + QRect(position, maskSize), + _overlayShadowScaled, + QRect(QPoint(), maskSize * ratio)); + } + q.setCompositionMode(QPainter::CompositionMode_DestinationOut); + q.drawImage(QRect(position, maskSize), *mask.image, mask.rect); + + if (cached) { + _validOverlayShadow[frameIndex] = true; + } + return result; +} + +void RoundAreaWithShadow::overlayExpandedBorder( + QPainter &p, + QSize size, + float64 expandRatio, + float64 radiusFrom, + float64 radiusTill, + float64 scale) { + const auto progress = expandRatio; + const auto frame = int(base::SafeRound(progress * (kFramesCount - 1))); + const auto cacheRatio = frame / float64(kFramesCount - 1); + const auto radius = radiusFrom + (radiusTill - radiusFrom) * cacheRatio; + const auto twiceRadius = int(base::SafeRound(radius * 2)); + const auto innerSize = QSize( + std::max(_inner.width(), twiceRadius), + std::max(_inner.height(), twiceRadius)); + + const auto overlayMask = validateOverlayMask( + frame, + innerSize, + radius, + twiceRadius, + scale); + const auto overlayShadow = validateOverlayShadow( + frame, + innerSize, + radius, + twiceRadius, + scale, + overlayMask); + + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + FillWithImage(p, QRect(QPoint(), size), overlayMask); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + FillWithImage(p, QRect(QPoint(), size), overlayShadow); +} + +QRect RoundAreaWithShadow::FillWithImage( + QPainter &p, + QRect geometry, + const ImageSubrect &pattern) { + const auto factor = style::DevicePixelRatio(); + const auto &image = *pattern.image; + const auto source = pattern.rect; + const auto sourceWidth = (source.width() / factor); + const auto sourceHeight = (source.height() / factor); + if (geometry.width() == sourceWidth) { + const auto part = (sourceHeight / 2) - 1; + const auto fill = geometry.height() - 2 * part; + const auto half = part * factor; + const auto top = source.height() - half; + p.drawImage( + geometry.topLeft(), + image, + QRect(source.x(), source.y(), source.width(), half)); + if (fill > 0) { + p.drawImage( + QRect( + geometry.topLeft() + QPoint(0, part), + QSize(sourceWidth, fill)), + image, + QRect( + source.x(), + source.y() + half, + source.width(), + top - half)); + } + p.drawImage( + geometry.topLeft() + QPoint(0, part + fill), + image, + QRect(source.x(), source.y() + top, source.width(), half)); + return QRect(); + } else if (geometry.height() == sourceHeight) { + const auto part = (sourceWidth / 2) - 1; + const auto fill = geometry.width() - 2 * part; + const auto half = part * factor; + const auto left = source.width() - half; + p.drawImage( + geometry.topLeft(), + image, + QRect(source.x(), source.y(), half, source.height())); + if (fill > 0) { + p.drawImage( + QRect( + geometry.topLeft() + QPoint(part, 0), + QSize(fill, sourceHeight)), + image, + QRect( + source.x() + half, + source.y(), + left - half, + source.height())); + } + p.drawImage( + geometry.topLeft() + QPoint(part + fill, 0), + image, + QRect(source.x() + left, source.y(), half, source.height())); + return QRect(); + } else if (geometry.width() > sourceWidth + && geometry.height() > sourceHeight) { + const auto xpart = (sourceWidth / 2) - 1; + const auto xfill = geometry.width() - 2 * xpart; + const auto xhalf = xpart * factor; + const auto left = source.width() - xhalf; + const auto ypart = (sourceHeight / 2) - 1; + const auto yfill = geometry.height() - 2 * ypart; + const auto yhalf = ypart * factor; + const auto top = source.height() - yhalf; + p.drawImage( + geometry.topLeft(), + image, + QRect(source.x(), source.y(), xhalf, yhalf)); + if (xfill > 0) { + p.drawImage( + QRect( + geometry.topLeft() + QPoint(xpart, 0), + QSize(xfill, ypart)), + image, + QRect( + source.x() + xhalf, + source.y(), + left - xhalf, + yhalf)); + } + p.drawImage( + geometry.topLeft() + QPoint(xpart + xfill, 0), + image, + QRect(source.x() + left, source.y(), xhalf, yhalf)); + + if (yfill > 0) { + p.drawImage( + QRect( + geometry.topLeft() + QPoint(0, ypart), + QSize(xpart, yfill)), + image, + QRect( + source.x(), + source.y() + yhalf, + xhalf, + top - yhalf)); + p.drawImage( + QRect( + geometry.topLeft() + QPoint(xpart + xfill, ypart), + QSize(xpart, yfill)), + image, + QRect( + source.x() + left, + source.y() + yhalf, + xhalf, + top - yhalf)); + } + + p.drawImage( + geometry.topLeft() + QPoint(0, ypart + yfill), + image, + QRect(source.x(), source.y() + top, xhalf, yhalf)); + if (xfill > 0) { + p.drawImage( + QRect( + geometry.topLeft() + QPoint(xpart, ypart + yfill), + QSize(xfill, ypart)), + image, + QRect( + source.x() + xhalf, + source.y() + top, + left - xhalf, + yhalf)); + } + p.drawImage( + geometry.topLeft() + QPoint(xpart + xfill, ypart + yfill), + image, + QRect(source.x() + left, source.y() + top, xhalf, yhalf)); + + return QRect( + geometry.topLeft() + QPoint(xpart, ypart), + QSize(xfill, yfill)); + } else { + Unexpected("Values in RoundAreaWithShadow::fillWithImage."); + } +} + +void RoundAreaWithShadow::setShadowColor(const QColor &shadow) { + if (_shadow == shadow) { + return; + } + _shadow = shadow; + ranges::fill(_validBg, false); + ranges::fill(_validShadow, false); + ranges::fill(_validOverlayShadow, false); +} + +QRect RoundAreaWithShadow::validateShadow( + int frameIndex, + float64 scale, + float64 radius) { + const auto rect = FrameCacheRect(frameIndex, kShadowCacheIndex, _outer); + if (_validShadow[frameIndex]) { + return rect; + } + + _shadowBuffer.fill(Qt::transparent); + auto p = QPainter(&_shadowBuffer); + auto hq = PainterHighQualityEnabler(p); + const auto center = _inner.center(); + const auto add = style::ConvertScale(2.5); + const auto shift = style::ConvertScale(0.5); + const auto big = QRectF(_inner).marginsAdded({ add, add, add, add }); + p.setPen(Qt::NoPen); + p.setBrush(_shadow); + if (scale != 1.) { + p.translate(center); + p.scale(scale, scale); + p.translate(-center); + } + p.drawRoundedRect(big.translated(0, shift), radius, radius); + p.end(); + _shadowBuffer = Images::Blur(std::move(_shadowBuffer)); + + auto q = QPainter(&_shadowParts); + q.setCompositionMode(QPainter::CompositionMode_Source); + q.drawImage(rect.topLeft() / style::DevicePixelRatio(), _shadowBuffer); + + _validShadow[frameIndex] = true; + return rect; +} + +void RoundAreaWithShadow::setBackgroundColor(const QColor &background) { + if (_background == background) { + return; + } + _background = background; + ranges::fill(_validBg, false); +} + +ImageSubrect RoundAreaWithShadow::validateFrame( + int frameIndex, + float64 scale, + float64 radius) { + const auto result = ImageSubrect{ + &_cacheBg, + FrameCacheRect(frameIndex, kBgCacheIndex, _outer) + }; + if (_validBg[frameIndex]) { + return result; + } + + const auto position = result.rect.topLeft() / style::DevicePixelRatio(); + const auto inner = _inner.translated(position); + const auto shadowSource = validateShadow(frameIndex, scale, radius); + + auto p = QPainter(&_cacheBg); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.drawImage(position, _shadowParts, shadowSource); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(_background); + if (scale != 1.) { + const auto center = inner.center(); + p.save(); + p.translate(center); + p.scale(scale, scale); + p.translate(-center); + } + p.drawRoundedRect(inner, radius, radius); + if (scale != 1.) { + p.restore(); + } + + _validBg[frameIndex] = true; + return result; +} + +} // namespace Ui diff --git a/ui/effects/round_area_with_shadow.h b/ui/effects/round_area_with_shadow.h new file mode 100644 index 0000000..0edd5be --- /dev/null +++ b/ui/effects/round_area_with_shadow.h @@ -0,0 +1,92 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +namespace Ui { + +struct ImageSubrect { + not_null image; + QRect rect; +}; + +class RoundAreaWithShadow final { +public: + static constexpr auto kFramesCount = 32; + + [[nodiscard]] static QImage PrepareImage(QSize size); + [[nodiscard]] static QImage PrepareFramesCache( + QSize frame, + int columns = 1); + [[nodiscard]] static QRect FrameCacheRect( + int frameIndex, + int column, + QSize frame); + + // Returns center area which could be just filled with a solid color. + static QRect FillWithImage( + QPainter &p, + QRect geometry, + const ImageSubrect &pattern); + + RoundAreaWithShadow(QSize inner, QMargins shadow, int twiceRadiusMax); + + void setBackgroundColor(const QColor &background); + void setShadowColor(const QColor &shadow); + + [[nodiscard]] ImageSubrect validateFrame( + int frameIndex, + float64 scale, + float64 radius); + [[nodiscard]] ImageSubrect validateOverlayMask( + int frameIndex, + QSize innerSize, + float64 radius, + int twiceRadius, + float64 scale); + [[nodiscard]] ImageSubrect validateOverlayShadow( + int frameIndex, + QSize innerSize, + float64 radius, + int twiceRadius, + float64 scale, + const ImageSubrect &mask); + + void overlayExpandedBorder( + QPainter &p, + QSize size, + float64 expandRatio, + float64 radiusFrom, + float64 radiusTill, + float64 scale); + +private: + [[nodiscard]] QRect validateShadow( + int frameIndex, + float64 scale, + float64 radius); + + QRect _inner; + QSize _outer; + QSize _overlay; + + std::array _validBg = { { false } }; + std::array _validShadow = { { false } }; + std::array _validOverlayMask = { { false } }; + std::array _validOverlayShadow = { { false } }; + QColor _background; + QColor _gradient; + QColor _shadow; + QImage _cacheBg; + QImage _shadowParts; + QImage _overlayCacheParts; + QImage _overlayMaskScaled; + QImage _overlayShadowScaled; + QImage _shadowBuffer; + +}; + +} // namespace Ui diff --git a/ui/effects/show_animation.cpp b/ui/effects/show_animation.cpp new file mode 100644 index 0000000..2e7a362 --- /dev/null +++ b/ui/effects/show_animation.cpp @@ -0,0 +1,110 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/effects/show_animation.h" + +#include "ui/effects/animations.h" +#include "ui/rp_widget.h" +#include "styles/style_widgets.h" + +namespace Ui::Animations { +namespace { + +void AnimateWidgets(const Widgets &targets, bool show) { + enum class Finish { + Bad, + Good, + }; + struct Object { + base::unique_qptr container; + QPointer weakTarget; + }; + struct State { + rpl::event_stream destroy; + Ui::Animations::Simple animation; + std::vector objects; + }; + auto lifetime = std::make_shared(); + const auto state = lifetime->make_state(); + + const auto from = show ? 0. : 1.; + const auto to = show ? 1. : 0.; + + for (const auto &target : targets) { + state->objects.push_back({ + base::make_unique_q(target->parentWidget()), + Ui::MakeWeak(target), + }); + + const auto pixmap = Ui::GrabWidget(target); + const auto raw = state->objects.back().container.get(); + + raw->paintRequest( + ) | rpl::start_with_next([=] { + QPainter p(raw); + + p.setOpacity(state->animation.value(to)); + p.drawPixmap(QPoint(), pixmap); + }, raw->lifetime()); + + target->geometryValue( + ) | rpl::start_with_next([=](const QRect &r) { + raw->setGeometry(r); + }, raw->lifetime()); + + raw->show(); + + if (!show) { + target->hide(); + } + } + + state->destroy.events( + ) | rpl::take( + 1 + ) | rpl::start_with_next([=](Finish type) mutable { + if (type == Finish::Good && show) { + for (const auto &object : state->objects) { + if (object.weakTarget) { + object.weakTarget->show(); + } + } + } + if (lifetime) { + base::take(lifetime)->destroy(); + } + }, *lifetime); + + state->animation.start( + [=](auto value) { + for (const auto &object : state->objects) { + object.container->update(); + + if (!object.weakTarget && show) { + state->destroy.fire(Finish::Bad); + return; + } + } + if (value == to) { + state->destroy.fire(Finish::Good); + } + }, + from, + to, + st::defaultToggle.duration); +} + +} // namespace + +void ShowWidgets(const Widgets &targets) { + AnimateWidgets(targets, true); +} + +void HideWidgets(const Widgets &targets) { + AnimateWidgets(targets, false); +} + +} // namespace Ui::Animations diff --git a/ui/effects/show_animation.h b/ui/effects/show_animation.h new file mode 100644 index 0000000..d75735d --- /dev/null +++ b/ui/effects/show_animation.h @@ -0,0 +1,20 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +namespace Ui { +class RpWidget; +} // namespace Ui + +namespace Ui::Animations { + +using Widgets = std::vector>; + +void ShowWidgets(const Widgets &targets); +void HideWidgets(const Widgets &targets); + +} // namespace Ui::Animations diff --git a/ui/effects/spoiler_mess.cpp b/ui/effects/spoiler_mess.cpp new file mode 100644 index 0000000..d4413de --- /dev/null +++ b/ui/effects/spoiler_mess.cpp @@ -0,0 +1,878 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/effects/spoiler_mess.h" + +#include "ui/effects/animations.h" +#include "ui/image/image_prepare.h" +#include "ui/painter.h" +#include "ui/integration.h" +#include "base/random.h" +#include "base/flags.h" + +#include +#include +#include + +#include +#include +#include +#include + +namespace Ui { +namespace { + +constexpr auto kVersion = 2; +constexpr auto kFramesPerRow = 10; +constexpr auto kImageSpoilerDarkenAlpha = 32; +constexpr auto kMaxCacheSize = 5 * 1024 * 1024; +constexpr auto kDefaultFrameDuration = crl::time(33); +constexpr auto kDefaultFramesCount = 60; +constexpr auto kAutoPauseTimeout = crl::time(1000); + +[[nodiscard]] SpoilerMessDescriptor DefaultDescriptorText() { + const auto ratio = style::DevicePixelRatio(); + const auto size = style::ConvertScale(128) * ratio; + return { + .particleFadeInDuration = crl::time(200), + .particleShownDuration = crl::time(200), + .particleFadeOutDuration = crl::time(200), + .particleSizeMin = style::ConvertScaleExact(1.5) * ratio, + .particleSizeMax = style::ConvertScaleExact(2.) * ratio, + .particleSpeedMin = style::ConvertScaleExact(4.), + .particleSpeedMax = style::ConvertScaleExact(8.), + .particleSpritesCount = 5, + .particlesCount = 9000, + .canvasSize = size, + .framesCount = kDefaultFramesCount, + .frameDuration = kDefaultFrameDuration, + }; +} + +[[nodiscard]] SpoilerMessDescriptor DefaultDescriptorImage() { + const auto ratio = style::DevicePixelRatio(); + const auto size = style::ConvertScale(128) * ratio; + return { + .particleFadeInDuration = crl::time(300), + .particleShownDuration = crl::time(0), + .particleFadeOutDuration = crl::time(300), + .particleSizeMin = style::ConvertScaleExact(1.5) * ratio, + .particleSizeMax = style::ConvertScaleExact(2.) * ratio, + .particleSpeedMin = style::ConvertScaleExact(10.), + .particleSpeedMax = style::ConvertScaleExact(20.), + .particleSpritesCount = 5, + .particlesCount = 3000, + .canvasSize = size, + .framesCount = kDefaultFramesCount, + .frameDuration = kDefaultFrameDuration, + }; +} + +} // namespace + +class SpoilerAnimationManager final { +public: + explicit SpoilerAnimationManager(not_null animation); + + void add(not_null animation); + void remove(not_null animation); + +private: + void destroyIfEmpty(); + + Ui::Animations::Basic _animation; + base::flat_set> _list; + +}; + +namespace { + +struct DefaultSpoilerWaiter { + std::condition_variable variable; + std::mutex mutex; +}; +struct DefaultSpoiler { + std::atomic cached/* = nullptr*/; + std::atomic waiter/* = nullptr*/; +}; +DefaultSpoiler DefaultTextMask; +DefaultSpoiler DefaultImageCached; + +SpoilerAnimationManager *DefaultAnimationManager/* = nullptr*/; + +struct Header { + uint32 version = 0; + uint32 dataLength = 0; + uint32 dataHash = 0; + int32 framesCount = 0; + int32 canvasSize = 0; + int32 frameDuration = 0; +}; + +struct Particle { + crl::time start = 0; + int spriteIndex = 0; + int x = 0; + int y = 0; + float64 dx = 0.; + float64 dy = 0.; +}; + +[[nodiscard]] std::pair RandomSpeed( + const SpoilerMessDescriptor &descriptor, + base::BufferedRandom &random) { + const auto count = descriptor.particlesCount; + const auto speedMax = descriptor.particleSpeedMax; + const auto speedMin = descriptor.particleSpeedMin; + const auto value = RandomIndex(2 * count + 2, random); + const auto negative = (value < count + 1); + const auto module = (negative ? value : (value - count - 1)); + const auto speed = speedMin + (((speedMax - speedMin) * module) / count); + const auto lifetime = descriptor.particleFadeInDuration + + descriptor.particleShownDuration + + descriptor.particleFadeOutDuration; + const auto max = int(std::ceil(speedMax * lifetime)); + const auto k = speed / lifetime; + const auto x = (speedMax > 0) + ? ((RandomIndex(2 * max + 1, random) - max) / float64(max)) + : 0.; + const auto y = (speedMax > 0) + ? (sqrt(1 - x * x) * (negative ? -1 : 1)) + : 0.; + return { k * x, k * y }; +} + +[[nodiscard]] Particle GenerateParticle( + const SpoilerMessDescriptor &descriptor, + int index, + base::BufferedRandom &random) { + const auto speed = RandomSpeed(descriptor, random); + return { + .start = (index * descriptor.framesCount * descriptor.frameDuration + / descriptor.particlesCount), + .spriteIndex = RandomIndex(descriptor.particleSpritesCount, random), + .x = RandomIndex(descriptor.canvasSize, random), + .y = RandomIndex(descriptor.canvasSize, random), + .dx = speed.first, + .dy = speed.second, + }; +} + +[[nodiscard]] QImage GenerateSprite( + const SpoilerMessDescriptor &descriptor, + int index, + int size, + base::BufferedRandom &random) { + Expects(index >= 0 && index < descriptor.particleSpritesCount); + + const auto count = descriptor.particleSpritesCount; + const auto middle = count / 2; + const auto min = descriptor.particleSizeMin; + const auto delta = descriptor.particleSizeMax - min; + const auto width = (index < middle) + ? (min + delta * (middle - index) / float64(middle)) + : min; + const auto height = (index > middle) + ? (min + delta * (index - middle) / float64(count - 1 - middle)) + : min; + const auto radius = min / 2.; + + auto result = QImage(size, size, QImage::Format_ARGB32_Premultiplied); + result.fill(Qt::transparent); + auto p = QPainter(&result); + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(Qt::white); + QPainterPath path; + path.addRoundedRect(1., 1., width, height, radius, radius); + p.drawPath(path); + p.end(); + return result; +} + +[[nodiscard]] QString DefaultMaskCacheFolder() { + const auto base = Integration::Instance().emojiCacheFolder(); + return base.isEmpty() ? QString() : (base + "/spoiler"); +} + +[[nodiscard]] std::optional ReadDefaultMask( + const QString &name, + std::optional validator) { + const auto folder = DefaultMaskCacheFolder(); + if (folder.isEmpty()) { + return {}; + } + auto file = QFile(folder + '/' + name); + return (file.open(QIODevice::ReadOnly) && file.size() <= kMaxCacheSize) + ? SpoilerMessCached::FromSerialized(file.readAll(), validator) + : std::nullopt; +} + +void WriteDefaultMask( + const QString &name, + const SpoilerMessCached &mask) { + const auto folder = DefaultMaskCacheFolder(); + if (!QDir().mkpath(folder)) { + return; + } + const auto bytes = mask.serialize(); + auto file = QFile(folder + '/' + name); + if (file.open(QIODevice::WriteOnly) && bytes.size() <= kMaxCacheSize) { + file.write(bytes); + } +} + +void Register(not_null animation) { + if (DefaultAnimationManager) { + DefaultAnimationManager->add(animation); + } else { + new SpoilerAnimationManager(animation); + } +} + +void Unregister(not_null animation) { + Expects(DefaultAnimationManager != nullptr); + + DefaultAnimationManager->remove(animation); +} + +// DescriptorFactory: (void) -> SpoilerMessDescriptor. +// Postprocess: (unique_ptr) -> unique_ptr. +template +void PrepareDefaultSpoiler( + DefaultSpoiler &spoiler, + const char *nameFactory, + DescriptorFactory descriptorFactory, + Postprocess postprocess) { + if (spoiler.waiter.load()) { + return; + } + const auto waiter = new DefaultSpoilerWaiter(); + auto expected = (DefaultSpoilerWaiter*)nullptr; + if (!spoiler.waiter.compare_exchange_strong(expected, waiter)) { + delete waiter; + return; + } + const auto name = QString::fromUtf8(nameFactory); + crl::async([=, &spoiler] { + const auto descriptor = descriptorFactory(); + auto cached = ReadDefaultMask(name, SpoilerMessCached::Validator{ + .frameDuration = descriptor.frameDuration, + .framesCount = descriptor.framesCount, + .canvasSize = descriptor.canvasSize, + }); + spoiler.cached = postprocess(cached + ? std::make_unique(std::move(*cached)) + : std::make_unique( + GenerateSpoilerMess(descriptor)) + ).release(); + auto lock = std::unique_lock(waiter->mutex); + waiter->variable.notify_all(); + if (!cached) { + WriteDefaultMask(name, *spoiler.cached); + } + }); +} + +[[nodiscard]] const SpoilerMessCached &WaitDefaultSpoiler( + DefaultSpoiler &spoiler) { + const auto &cached = spoiler.cached; + if (const auto result = cached.load()) { + return *result; + } + const auto waiter = spoiler.waiter.load(); + Assert(waiter != nullptr); + while (true) { + auto lock = std::unique_lock(waiter->mutex); + if (const auto result = cached.load()) { + return *result; + } + waiter->variable.wait(lock); + } +} + +} // namespace + +SpoilerAnimationManager::SpoilerAnimationManager( + not_null animation) +: _animation([=](crl::time now) { + for (auto i = begin(_list); i != end(_list);) { + if ((*i)->repaint(now)) { + ++i; + } else { + i = _list.erase(i); + } + } + destroyIfEmpty(); +}) +, _list{ { animation } } { + Expects(!DefaultAnimationManager); + + DefaultAnimationManager = this; + _animation.start(); +} + +void SpoilerAnimationManager::add(not_null animation) { + _list.emplace(animation); +} + +void SpoilerAnimationManager::remove(not_null animation) { + _list.remove(animation); + destroyIfEmpty(); +} + +void SpoilerAnimationManager::destroyIfEmpty() { + if (_list.empty()) { + Assert(DefaultAnimationManager == this); + delete base::take(DefaultAnimationManager); + } +} + +SpoilerMessCached GenerateSpoilerMess( + const SpoilerMessDescriptor &descriptor) { + Expects(descriptor.framesCount > 0); + Expects(descriptor.frameDuration > 0); + Expects(descriptor.particlesCount > 0); + Expects(descriptor.canvasSize > 0); + Expects(descriptor.particleSizeMax >= descriptor.particleSizeMin); + Expects(descriptor.particleSizeMin > 0.); + + const auto frames = descriptor.framesCount; + const auto rows = (frames + kFramesPerRow - 1) / kFramesPerRow; + const auto columns = std::min(frames, kFramesPerRow); + const auto size = descriptor.canvasSize; + const auto count = descriptor.particlesCount; + const auto width = size * columns; + const auto height = size * rows; + const auto spriteSize = 2 + int(std::ceil(descriptor.particleSizeMax)); + const auto singleDuration = descriptor.particleFadeInDuration + + descriptor.particleShownDuration + + descriptor.particleFadeOutDuration; + const auto fullDuration = frames * descriptor.frameDuration; + Assert(fullDuration > singleDuration); + + auto random = base::BufferedRandom(count * 5); + + auto particles = std::vector(); + particles.reserve(descriptor.particlesCount); + for (auto i = 0; i != descriptor.particlesCount; ++i) { + particles.push_back(GenerateParticle(descriptor, i, random)); + } + + auto sprites = std::vector(); + sprites.reserve(descriptor.particleSpritesCount); + for (auto i = 0; i != descriptor.particleSpritesCount; ++i) { + sprites.push_back(GenerateSprite(descriptor, i, spriteSize, random)); + } + + auto frame = 0; + auto image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::transparent); + auto p = QPainter(&image); + const auto paintOneAt = [&](const Particle &particle, crl::time now) { + if (now <= 0 || now >= singleDuration) { + return; + } + const auto clamp = [&](int value) { + return ((value % size) + size) % size; + }; + const auto x = clamp( + particle.x + int(base::SafeRound(now * particle.dx))); + const auto y = clamp( + particle.y + int(base::SafeRound(now * particle.dy))); + const auto opacity = (now < descriptor.particleFadeInDuration) + ? (now / float64(descriptor.particleFadeInDuration)) + : (now > singleDuration - descriptor.particleFadeOutDuration) + ? ((singleDuration - now) + / float64(descriptor.particleFadeOutDuration)) + : 1.; + p.setOpacity(opacity); + const auto &sprite = sprites[particle.spriteIndex]; + p.drawImage(x, y, sprite); + if (x + spriteSize > size) { + p.drawImage(x - size, y, sprite); + if (y + spriteSize > size) { + p.drawImage(x, y - size, sprite); + p.drawImage(x - size, y - size, sprite); + } + } else if (y + spriteSize > size) { + p.drawImage(x, y - size, sprite); + } + }; + const auto paintOne = [&](const Particle &particle, crl::time now) { + paintOneAt(particle, now - particle.start); + paintOneAt(particle, now + fullDuration - particle.start); + }; + for (auto y = 0; y != rows; ++y) { + for (auto x = 0; x != columns; ++x) { + const auto rect = QRect(x * size, y * size, size, size); + p.setClipRect(rect); + p.translate(rect.topLeft()); + const auto time = frame * descriptor.frameDuration; + for (auto index = 0; index != count; ++index) { + paintOne(particles[index], time); + } + p.translate(-rect.topLeft()); + if (++frame >= frames) { + break; + } + } + } + return SpoilerMessCached( + std::move(image), + frames, + descriptor.frameDuration, + size); +} + +void FillSpoilerRect( + QPainter &p, + QRect rect, + const SpoilerMessFrame &frame, + QPoint originShift) { + if (rect.isEmpty()) { + return; + } + const auto &image = *frame.image; + const auto source = frame.source; + const auto ratio = style::DevicePixelRatio(); + const auto origin = rect.topLeft() + originShift; + const auto size = source.width() / ratio; + const auto xSkipFrames = (origin.x() <= rect.x()) + ? ((rect.x() - origin.x()) / size) + : -((origin.x() - rect.x() + size - 1) / size); + const auto ySkipFrames = (origin.y() <= rect.y()) + ? ((rect.y() - origin.y()) / size) + : -((origin.y() - rect.y() + size - 1) / size); + const auto xFrom = origin.x() + size * xSkipFrames; + const auto yFrom = origin.y() + size * ySkipFrames; + Assert((xFrom <= rect.x()) + && (yFrom <= rect.y()) + && (xFrom + size > rect.x()) + && (yFrom + size > rect.y())); + const auto xTill = rect.x() + rect.width(); + const auto yTill = rect.y() + rect.height(); + const auto xCount = (xTill - xFrom + size - 1) / size; + const auto yCount = (yTill - yFrom + size - 1) / size; + Assert(xCount > 0 && yCount > 0); + const auto xFullFrom = (xFrom < rect.x()) ? 1 : 0; + const auto yFullFrom = (yFrom < rect.y()) ? 1 : 0; + const auto xFullTill = xCount - (xFrom + xCount * size > xTill ? 1 : 0); + const auto yFullTill = yCount - (yFrom + yCount * size > yTill ? 1 : 0); + const auto targetRect = [&](int x, int y) { + return QRect(xFrom + x * size, yFrom + y * size, size, size); + }; + const auto drawFull = [&](int x, int y) { + p.drawImage(targetRect(x, y), image, source); + }; + const auto drawPart = [&](int x, int y) { + const auto target = targetRect(x, y); + const auto fill = target.intersected(rect); + Assert(!fill.isEmpty()); + p.drawImage(fill, image, QRect( + source.topLeft() + ((fill.topLeft() - target.topLeft()) * ratio), + fill.size() * ratio)); + }; + if (yFullFrom) { + for (auto x = 0; x != xCount; ++x) { + drawPart(x, 0); + } + } + if (yFullFrom < yFullTill) { + if (xFullFrom) { + for (auto y = yFullFrom; y != yFullTill; ++y) { + drawPart(0, y); + } + } + if (xFullFrom < xFullTill) { + for (auto y = yFullFrom; y != yFullTill; ++y) { + for (auto x = xFullFrom; x != xFullTill; ++x) { + drawFull(x, y); + } + } + } + if (xFullFrom <= xFullTill && xFullTill < xCount) { + for (auto y = yFullFrom; y != yFullTill; ++y) { + drawPart(xFullTill, y); + } + } + } + if (yFullFrom <= yFullTill && yFullTill < yCount) { + for (auto x = 0; x != xCount; ++x) { + drawPart(x, yFullTill); + } + } +} + +void FillSpoilerRect( + QPainter &p, + QRect rect, + Images::CornersMaskRef mask, + const SpoilerMessFrame &frame, + QImage &cornerCache, + QPoint originShift) { + using namespace Images; + + if ((!mask.p[kTopLeft] || mask.p[kTopLeft]->isNull()) + && (!mask.p[kTopRight] || mask.p[kTopRight]->isNull()) + && (!mask.p[kBottomLeft] || mask.p[kBottomLeft]->isNull()) + && (!mask.p[kBottomRight] || mask.p[kBottomRight]->isNull())) { + FillSpoilerRect(p, rect, frame, originShift); + return; + } + const auto ratio = style::DevicePixelRatio(); + const auto cornerSize = [&](int index) { + const auto corner = mask.p[index]; + return (!corner || corner->isNull()) ? 0 : (corner->width() / ratio); + }; + const auto verticalSkip = [&](int left, int right) { + return std::max(cornerSize(left), cornerSize(right)); + }; + const auto fillBg = [&](QRect part) { + FillSpoilerRect( + p, + part.translated(rect.topLeft()), + frame, + originShift - rect.topLeft() - part.topLeft()); + }; + const auto fillCorner = [&](int x, int y, int index) { + const auto position = QPoint(x, y); + const auto corner = mask.p[index]; + if (!corner || corner->isNull()) { + return; + } + if (cornerCache.width() < corner->width() + || cornerCache.height() < corner->height()) { + cornerCache = QImage( + std::max(cornerCache.width(), corner->width()), + std::max(cornerCache.height(), corner->height()), + QImage::Format_ARGB32_Premultiplied); + cornerCache.setDevicePixelRatio(ratio); + } + const auto size = corner->size() / ratio; + const auto target = QRect(QPoint(), size); + auto q = QPainter(&cornerCache); + q.setCompositionMode(QPainter::CompositionMode_Source); + FillSpoilerRect( + q, + target, + frame, + originShift - rect.topLeft() - position); + q.setCompositionMode(QPainter::CompositionMode_DestinationIn); + q.drawImage(target, *corner); + q.end(); + p.drawImage( + QRect(rect.topLeft() + position, size), + cornerCache, + QRect(QPoint(), corner->size())); + }; + const auto top = verticalSkip(kTopLeft, kTopRight); + const auto bottom = verticalSkip(kBottomLeft, kBottomRight); + if (top) { + const auto left = cornerSize(kTopLeft); + const auto right = cornerSize(kTopRight); + if (left) { + fillCorner(0, 0, kTopLeft); + if (const auto add = top - left) { + fillBg({ 0, left, left, add }); + } + } + if (const auto fill = rect.width() - left - right; fill > 0) { + fillBg({ left, 0, fill, top }); + } + if (right) { + fillCorner(rect.width() - right, 0, kTopRight); + if (const auto add = top - right) { + fillBg({ rect.width() - right, right, right, add }); + } + } + } + if (const auto h = rect.height() - top - bottom; h > 0) { + fillBg({ 0, top, rect.width(), h }); + } + if (bottom) { + const auto left = cornerSize(kBottomLeft); + const auto right = cornerSize(kBottomRight); + if (left) { + fillCorner(0, rect.height() - left, kBottomLeft); + if (const auto add = bottom - left) { + fillBg({ 0, rect.height() - bottom, left, add }); + } + } + if (const auto fill = rect.width() - left - right; fill > 0) { + fillBg({ left, rect.height() - bottom, fill, bottom }); + } + if (right) { + fillCorner( + rect.width() - right, + rect.height() - right, + kBottomRight); + if (const auto add = bottom - right) { + fillBg({ + rect.width() - right, + rect.height() - bottom, + right, + add, + }); + } + } + } +} + +SpoilerMessCached::SpoilerMessCached( + QImage image, + int framesCount, + crl::time frameDuration, + int canvasSize) +: _image(std::move(image)) +, _frameDuration(frameDuration) +, _framesCount(framesCount) +, _canvasSize(canvasSize) { + Expects(_frameDuration > 0); + Expects(_framesCount > 0); + Expects(_canvasSize > 0); + Expects(_image.size() == QSize( + std::min(_framesCount, kFramesPerRow) * _canvasSize, + ((_framesCount + kFramesPerRow - 1) / kFramesPerRow) * _canvasSize)); +} + +SpoilerMessCached::SpoilerMessCached( + const SpoilerMessCached &mask, + const QColor &color) +: SpoilerMessCached( + style::colorizeImage(*mask.frame(0).image, color), + mask.framesCount(), + mask.frameDuration(), + mask.canvasSize()) { +} + +SpoilerMessFrame SpoilerMessCached::frame(int index) const { + const auto row = index / kFramesPerRow; + const auto column = index - row * kFramesPerRow; + return { + .image = &_image, + .source = QRect( + column * _canvasSize, + row * _canvasSize, + _canvasSize, + _canvasSize), + }; +} + +SpoilerMessFrame SpoilerMessCached::frame() const { + return frame((crl::now() / _frameDuration) % _framesCount); +} + +crl::time SpoilerMessCached::frameDuration() const { + return _frameDuration; +} + +int SpoilerMessCached::framesCount() const { + return _framesCount; +} + +int SpoilerMessCached::canvasSize() const { + return _canvasSize; +} + +QByteArray SpoilerMessCached::serialize() const { + Expects(_frameDuration < std::numeric_limits::max()); + + const auto skip = sizeof(Header); + auto result = QByteArray(skip, Qt::Uninitialized); + auto header = Header{ + .version = kVersion, + .framesCount = _framesCount, + .canvasSize = _canvasSize, + .frameDuration = int32(_frameDuration), + }; + const auto width = int(_image.width()); + const auto height = int(_image.height()); + auto grayscale = QImage(width, height, QImage::Format_Grayscale8); + { + auto tobytes = grayscale.bits(); + auto frombytes = _image.constBits(); + const auto toadd = grayscale.bytesPerLine() - width; + const auto fromadd = _image.bytesPerLine() - (width * 4); + for (auto y = 0; y != height; ++y) { + for (auto x = 0; x != width; ++x) { + *tobytes++ = *frombytes; + frombytes += 4; + } + tobytes += toadd; + frombytes += fromadd; + } + } + + auto device = QBuffer(&result); + device.open(QIODevice::WriteOnly); + device.seek(skip); + grayscale.save(&device, "PNG"); + device.close(); + header.dataLength = result.size() - skip; + header.dataHash = XXH32(result.data() + skip, header.dataLength, 0); + memcpy(result.data(), &header, skip); + return result; +} + +std::optional SpoilerMessCached::FromSerialized( + QByteArray data, + std::optional validator) { + const auto skip = sizeof(Header); + const auto length = data.size(); + const auto bytes = reinterpret_cast(data.constData()); + if (length <= skip) { + return {}; + } + auto header = Header(); + memcpy(&header, bytes, skip); + if (header.version != kVersion + || header.canvasSize <= 0 + || header.framesCount <= 0 + || header.frameDuration <= 0 + || (validator + && (validator->frameDuration != header.frameDuration + || validator->framesCount != header.framesCount + || validator->canvasSize != header.canvasSize)) + || (skip + header.dataLength != length) + || (XXH32(bytes + skip, header.dataLength, 0) != header.dataHash)) { + return {}; + } + auto grayscale = QImage(); + if (!grayscale.loadFromData(bytes + skip, header.dataLength, "PNG") + || (grayscale.format() != QImage::Format_Grayscale8)) { + return {}; + } + const auto count = header.framesCount; + const auto rows = (count + kFramesPerRow - 1) / kFramesPerRow; + const auto columns = std::min(count, kFramesPerRow); + const auto width = grayscale.width(); + const auto height = grayscale.height(); + if (QSize(width, height) != QSize(columns, rows) * header.canvasSize) { + return {}; + } + auto image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + { + Assert(image.bytesPerLine() % 4 == 0); + auto toints = reinterpret_cast(image.bits()); + auto frombytes = grayscale.constBits(); + const auto toadd = (image.bytesPerLine() / 4) - width; + const auto fromadd = grayscale.bytesPerLine() - width; + for (auto y = 0; y != height; ++y) { + for (auto x = 0; x != width; ++x) { + const auto byte = uint32(*frombytes++); + *toints++ = (byte << 24) | (byte << 16) | (byte << 8) | byte; + } + toints += toadd; + frombytes += fromadd; + } + + } + return SpoilerMessCached( + std::move(image), + count, + header.frameDuration, + header.canvasSize); +} + +SpoilerAnimation::SpoilerAnimation(Fn repaint) +: _repaint(std::move(repaint)) { + Expects(_repaint != nullptr); +} + +SpoilerAnimation::~SpoilerAnimation() { + if (_animating) { + _animating = false; + Unregister(this); + } +} + +int SpoilerAnimation::index(crl::time now, bool paused) { + _scheduled = false; + const auto add = std::min(now - _last, kDefaultFrameDuration); + if (anim::Disabled()) { + paused = true; + } + if (!paused || _last) { + _accumulated += add; + _last = paused ? 0 : now; + } + const auto absolute = (_accumulated / kDefaultFrameDuration); + if (!paused && !_animating) { + _animating = true; + Register(this); + } else if (paused && _animating) { + _animating = false; + Unregister(this); + } + return absolute % kDefaultFramesCount; +} + +Fn SpoilerAnimation::repaintCallback() const { + return _repaint; +} + +bool SpoilerAnimation::repaint(crl::time now) { + if (!_scheduled) { + _scheduled = true; + _repaint(); + } else if (_animating && _last && _last + kAutoPauseTimeout <= now) { + _animating = false; + return false; + } + return true; +} + +void PreloadTextSpoilerMask() { + PrepareDefaultSpoiler( + DefaultTextMask, + "text", + DefaultDescriptorText, + [](std::unique_ptr cached) { return cached; }); +} + +const SpoilerMessCached &DefaultTextSpoilerMask() { + [[maybe_unused]] static const auto once = [&] { + PreloadTextSpoilerMask(); + return 0; + }(); + return WaitDefaultSpoiler(DefaultTextMask); +} + +void PreloadImageSpoiler() { + const auto postprocess = [](std::unique_ptr cached) { + Expects(cached != nullptr); + + const auto frame = cached->frame(0); + auto image = QImage( + frame.image->size(), + QImage::Format_ARGB32_Premultiplied); + image.fill(QColor(0, 0, 0, kImageSpoilerDarkenAlpha)); + auto p = QPainter(&image); + p.drawImage(0, 0, *frame.image); + p.end(); + return std::make_unique( + std::move(image), + cached->framesCount(), + cached->frameDuration(), + cached->canvasSize()); + }; + PrepareDefaultSpoiler( + DefaultImageCached, + "image", + DefaultDescriptorImage, + postprocess); +} + +const SpoilerMessCached &DefaultImageSpoiler() { + [[maybe_unused]] static const auto once = [&] { + PreloadImageSpoiler(); + return 0; + }(); + return WaitDefaultSpoiler(DefaultImageCached); +} + +} // namespace Ui diff --git a/ui/effects/spoiler_mess.h b/ui/effects/spoiler_mess.h new file mode 100644 index 0000000..759f3fe --- /dev/null +++ b/ui/effects/spoiler_mess.h @@ -0,0 +1,117 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +#include + +namespace Images { +struct CornersMaskRef; +} // namespace Images + +namespace Ui { + +struct SpoilerMessDescriptor { + crl::time particleFadeInDuration = 0; + crl::time particleShownDuration = 0; + crl::time particleFadeOutDuration = 0; + float64 particleSizeMin = 0.; + float64 particleSizeMax = 0.; + float64 particleSpeedMin = 0.; + float64 particleSpeedMax = 0.; + int particleSpritesCount = 0; + int particlesCount = 0; + int canvasSize = 0; + int framesCount = 0; + crl::time frameDuration = 0; +}; + +struct SpoilerMessFrame { + not_null image; + QRect source; +}; + +void FillSpoilerRect( + QPainter &p, + QRect rect, + const SpoilerMessFrame &frame, + QPoint originShift = {}); + +void FillSpoilerRect( + QPainter &p, + QRect rect, + Images::CornersMaskRef mask, + const SpoilerMessFrame &frame, + QImage &cornerCache, + QPoint originShift = {}); + +class SpoilerMessCached final { +public: + SpoilerMessCached( + QImage image, + int framesCount, + crl::time frameDuration, + int canvasSize); + SpoilerMessCached(const SpoilerMessCached &mask, const QColor &color); + + [[nodiscard]] SpoilerMessFrame frame(int index) const; + [[nodiscard]] SpoilerMessFrame frame() const; // Current by time. + + [[nodiscard]] crl::time frameDuration() const; + [[nodiscard]] int framesCount() const; + [[nodiscard]] int canvasSize() const; + + struct Validator { + crl::time frameDuration = 0; + int framesCount = 0; + int canvasSize = 0; + }; + [[nodiscard]] QByteArray serialize() const; + [[nodiscard]] static std::optional FromSerialized( + QByteArray data, + std::optional validator = {}); + +private: + QImage _image; + crl::time _frameDuration = 0; + int _framesCount = 0; + int _canvasSize = 0; + +}; + +// Works with default frame duration and default frame count. +class SpoilerAnimationManager; +class SpoilerAnimation final { +public: + explicit SpoilerAnimation(Fn repaint); + ~SpoilerAnimation(); + + [[nodiscard]] int index(crl::time now, bool paused); + + [[nodiscard]] Fn repaintCallback() const; + +private: + friend class SpoilerAnimationManager; + + [[nodiscard]] bool repaint(crl::time now); + + const Fn _repaint; + crl::time _accumulated = 0; + crl::time _last = 0; + bool _animating : 1 = false; + bool _scheduled : 1 = false; + +}; + +[[nodiscard]] SpoilerMessCached GenerateSpoilerMess( + const SpoilerMessDescriptor &descriptor); + +void PreloadTextSpoilerMask(); +[[nodiscard]] const SpoilerMessCached &DefaultTextSpoilerMask(); +void PreloadImageSpoiler(); +[[nodiscard]] const SpoilerMessCached &DefaultImageSpoiler(); + +} // namespace Ui diff --git a/ui/emoji_config.cpp b/ui/emoji_config.cpp index 6b43bcf..349d939 100644 --- a/ui/emoji_config.cpp +++ b/ui/emoji_config.cpp @@ -31,7 +31,7 @@ constexpr auto kUniversalSize = 72; constexpr auto kImagesPerRow = 32; constexpr auto kImageRowsPerSprite = 16; -constexpr auto kSetVersion = uint32(3); +constexpr auto kSetVersion = uint32(5); constexpr auto kCacheVersion = uint32(7); constexpr auto kMaxId = uint32(1 << 8); @@ -124,12 +124,9 @@ uint32 ComputeVersion(int id) { static_assert(kCacheVersion > 0 && kCacheVersion < (1 << 16)); static_assert(kSetVersion > 0 && kSetVersion < (1 << 8)); - auto result = uint32(kCacheVersion); - if (!id) { - return result; - } - result |= (uint32(id) << 24) | (uint32(kSetVersion) << 16); - return result; + return uint32(kCacheVersion) + | (uint32(kSetVersion) << 16) + | (uint32(id) << 24); } int ReadCurrentSetId() { @@ -366,11 +363,31 @@ std::vector LoadAndValidateSprites(int id) { void ClearUniversalChecked() { Expects(InstanceNormal != nullptr && InstanceLarge != nullptr); - if (CanClearUniversal - && Universal + if (Universal && InstanceNormal->cached() && InstanceLarge->cached()) { - Universal->clear(); + if (CanClearUniversal) { + Universal->clear(); + } + ClearIrrelevantCache(); + } +} + +[[nodiscard]] uint8 EmojiSurrogatePairs(const QString &e) { + if (e.size() > 1) { + auto count = uint8(0); + const auto begin = e.data(); + auto ch = begin; + for (const auto end = begin + e.size(); ch != end; ++ch) { + if ((ch + 1 < end) + && ch->isHighSurrogate() + && (ch + 1)->isLowSurrogate()) { + count++; + } + } + return count; + } else { + return 0; } } @@ -490,8 +507,8 @@ void Init() { const auto persprite = kImagesPerRow * kImageRowsPerSprite; SpritesCount = (count / persprite) + ((count % persprite) ? 1 : 0); - SizeNormal = style::ConvertScale(18, style::Scale() * style::DevicePixelRatio()); - SizeLarge = int(style::ConvertScale(18 * 4 / 3., style::Scale() * style::DevicePixelRatio())); + SizeNormal = st::emojiSize * style::DevicePixelRatio(); + SizeLarge = int(style::ConvertScale(18 * 4 / 3., style::Scale())) * style::DevicePixelRatio(); Universal = std::make_shared(ReadCurrentSetId()); CanClearUniversal = false; @@ -628,6 +645,22 @@ int GetSizeTouchbar() { } #endif +One::One( + const QString &id, + EmojiPtr original, + uint32 index, + bool hasPostfix, + bool colorizable, + const CreationTag &) +: _id(id) +, _original(original) +, _index(index) +, _hasPostfix(hasPostfix) +, _colorizable(colorizable) +, _surrogatePairs(EmojiSurrogatePairs(text())) { + Expects(!_colorizable || !colored()); +} + int One::variantsCount() const { return hasVariants() ? 5 : 0; } diff --git a/ui/emoji_config.h b/ui/emoji_config.h index 95dd23b..30fbc77 100644 --- a/ui/emoji_config.h +++ b/ui/emoji_config.h @@ -51,66 +51,70 @@ class One { public: One(One &&other) = default; - One(const QString &id, EmojiPtr original, uint32 index, bool hasPostfix, bool colorizable, const CreationTag &) - : _id(id) - , _original(original) - , _index(index) - , _hasPostfix(hasPostfix) - , _colorizable(colorizable) { - Expects(!_colorizable || !colored()); - } + One( + const QString &id, + EmojiPtr original, + uint32 index, + bool hasPostfix, + bool colorizable, + const CreationTag &); - QString id() const { + [[nodiscard]] QString id() const { return _id; } - QString text() const { + [[nodiscard]] QString text() const { return hasPostfix() ? (_id + QChar(kPostfix)) : _id; } - bool colored() const { + [[nodiscard]] bool colored() const { return (_original != nullptr); } - EmojiPtr original() const { + [[nodiscard]] EmojiPtr original() const { return _original ? _original : this; } - QString nonColoredId() const { + [[nodiscard]] QString nonColoredId() const { return original()->id(); } - bool hasPostfix() const { + [[nodiscard]] bool hasPostfix() const { return _hasPostfix; } - bool hasVariants() const { + [[nodiscard]] bool hasVariants() const { return _colorizable || colored(); } - int variantsCount() const; - int variantIndex(EmojiPtr variant) const; - EmojiPtr variant(int index) const; + [[nodiscard]] int variantsCount() const; + [[nodiscard]] int variantIndex(EmojiPtr variant) const; + [[nodiscard]] EmojiPtr variant(int index) const; - int index() const { + [[nodiscard]] int index() const { return _index; } - int sprite() const { + [[nodiscard]] int sprite() const { return int(_index >> 9); } - int row() const { + [[nodiscard]] int row() const { return int((_index >> 5) & 0x0FU); } - int column() const { + [[nodiscard]] int column() const { return int(_index & 0x1FU); } - QString toUrl() const { + [[nodiscard]] QString toUrl() const { return "emoji://e." + QString::number(index()); } + [[nodiscard]] uint8 surrogatePairs() const { + return _surrogatePairs; + } + private: const QString _id; const EmojiPtr _original = nullptr; const uint32 _index = 0; const bool _hasPostfix = false; const bool _colorizable = false; + const uint8 _surrogatePairs; friend void internal::Init(); diff --git a/ui/gl/gl_detection.cpp b/ui/gl/gl_detection.cpp index 7c7ea3f..150eb8b 100644 --- a/ui/gl/gl_detection.cpp +++ b/ui/gl/gl_detection.cpp @@ -10,12 +10,15 @@ #include "ui/integration.h" #include "base/debug_log.h" #include "base/options.h" +#include "base/platform/base_platform_info.h" #include #include +#include #include #include #include +#include #include #ifdef Q_OS_WIN @@ -32,7 +35,7 @@ namespace { bool ForceDisabled/* = false*/; #ifdef Q_OS_WIN -ANGLE ResolvedANGLE = ANGLE::Auto; +ANGLE ResolvedANGLE/* = ANGLE::Auto*/; #endif // Q_OS_WIN base::options::toggle AllowLinuxNvidiaOpenGL({ @@ -55,7 +58,7 @@ void CrashCheckStart() { const char kOptionAllowLinuxNvidiaOpenGL[] = "allow-linux-nvidia-opengl"; -Capabilities CheckCapabilities(QWidget *widget) { +Capabilities CheckCapabilities(QWidget *widget, bool avoidWidgetCreation) { if (ForceDisabled) { LOG_ONCE(("OpenGL: Force-disabled.")); return {}; @@ -79,31 +82,51 @@ Capabilities CheckCapabilities(QWidget *widget) { LOG(("OpenGL: Could not create window for widget.")); return {}; } - if (!widget->window()->windowHandle()->supportsOpenGL()) { - LOG_ONCE(("OpenGL: Not supported for window.")); - return {}; - } format = widget->window()->windowHandle()->format(); format.setAlphaBufferSize(8); widget->window()->windowHandle()->setFormat(format); } else { format.setAlphaBufferSize(8); } - auto tester = QOpenGLWidget(widget); - tester.setFormat(format); CrashCheckStart(); - tester.grabFramebuffer(); // Force initialize(). + const auto tester = [&] { + std::unique_ptr result; + if (avoidWidgetCreation) { + const auto w = new QOpenGLWindow(); + auto e = QResizeEvent(QSize(), QSize()); + w->setFormat(format); + w->create(); + static_cast(w)->event(&e); // Force initialize(). + w->grabFramebuffer(); // Force makeCurrent(). + result.reset(w); + } else { + const auto w = new QOpenGLWidget(widget); + w->setFormat(format); + w->grabFramebuffer(); // Force initialize(). + if (!w->window()->windowHandle()) { + w->window()->createWinId(); + } + result.reset(w); + } + return result; + }(); + const auto testerWidget = avoidWidgetCreation + ? nullptr + : static_cast(tester.get()); + const auto testerWindow = avoidWidgetCreation + ? static_cast(tester.get()) + : nullptr; + /*const auto testerQWindow = avoidWidgetCreation + ? static_cast(tester.get()) + : testerWidget->window()->windowHandle();*/ CrashCheckFinish(); - if (!tester.window()->windowHandle()) { - tester.window()->createWinId(); - } - const auto context = tester.context(); + const auto context = avoidWidgetCreation ? testerWindow->context() : testerWidget->context(); if (!context || !context->isValid()/* // This check doesn't work for a widget with WA_NativeWindow. - || !context->makeCurrent(tester.window()->windowHandle())*/) { + || !context->makeCurrent(testerQWindow)*/) { LOG_ONCE(("OpenGL: Could not create widget in a window.")); return {}; } @@ -163,8 +186,9 @@ Capabilities CheckCapabilities(QWidget *widget) { const auto version = reinterpret_cast( functions->glGetString(GL_VERSION)); LOG(("OpenGL Version: %1").arg(version ? version : "[nullptr]")); + const auto extensions = context->extensions(); auto list = QStringList(); - for (const auto &extension : context->extensions()) { + for (const auto &extension : extensions) { list.append(QString::fromLatin1(extension)); } LOG(("OpenGL Extensions: %1").arg(list.join(", "))); @@ -177,8 +201,9 @@ Capabilities CheckCapabilities(QWidget *widget) { LOG(("EGL Extensions: %1").arg(egllist.join(", "))); #endif // Q_OS_WIN -#ifdef Q_OS_LINUX - if (version && QByteArray(version).contains("NVIDIA")) { + if (::Platform::IsLinux() + && version + && QByteArray(version).contains("NVIDIA")) { // https://github.com/telegramdesktop/tdesktop/issues/16830 if (AllowLinuxNvidiaOpenGL.value()) { LOG_ONCE(("OpenGL: Allow on NVIDIA driver (experimental).")); @@ -187,7 +212,6 @@ Capabilities CheckCapabilities(QWidget *widget) { return false; } } -#endif // Q_OS_LINUX return true; }(); @@ -210,6 +234,15 @@ Capabilities CheckCapabilities(QWidget *widget) { return result; } +Backend ChooseBackendDefault(Capabilities capabilities) { + const auto use = ::Platform::IsMac() + ? true + : ::Platform::IsWindows() + ? capabilities.supported + : capabilities.transparency; + return use ? Backend::OpenGL : Backend::Raster; +} + bool LastCrashCheckFailed() { return QFile::exists(Integration::Instance().openglCheckFilePath()); } @@ -241,7 +274,7 @@ void ConfigureANGLE() { qputenv("DESKTOP_APP_QT_ANGLE_PLATFORM", backend); } }; - check("gl", ANGLE::OpenGL); + //check("gl", ANGLE::OpenGL); check("d3d9", ANGLE::D3D9); check("d3d11", ANGLE::D3D11); check("d3d11on12", ANGLE::D3D11on12); @@ -266,7 +299,7 @@ void ChangeANGLE(ANGLE backend) { case ANGLE::D3D9: write("d3d9"); break; case ANGLE::D3D11: write("d3d11"); break; case ANGLE::D3D11on12: write("d3d11on12"); break; - case ANGLE::OpenGL: write("gl"); break; + //case ANGLE::OpenGL: write("gl"); break; default: Unexpected("ANGLE backend value."); } } diff --git a/ui/gl/gl_detection.h b/ui/gl/gl_detection.h index 45978ae..97e6606 100644 --- a/ui/gl/gl_detection.h +++ b/ui/gl/gl_detection.h @@ -24,7 +24,10 @@ struct Capabilities { bool transparency = false; }; -[[nodiscard]] Capabilities CheckCapabilities(QWidget *widget = nullptr); +[[nodiscard]] Capabilities CheckCapabilities( + QWidget *widget = nullptr, + bool avoidWidgetCreation = false); +[[nodiscard]] Backend ChooseBackendDefault(Capabilities capabilities); void ForceDisable(bool disable); @@ -37,7 +40,7 @@ enum class ANGLE { D3D9, D3D11, D3D11on12, - OpenGL, + //OpenGL, }; void ConfigureANGLE(); // Requires Ui::Integration being set. diff --git a/ui/gl/gl_image.cpp b/ui/gl/gl_image.cpp index fc0e348..cb04fdd 100644 --- a/ui/gl/gl_image.cpp +++ b/ui/gl/gl_image.cpp @@ -73,6 +73,7 @@ QImage Image::takeImage() { void Image::invalidate() { _storage = base::take(_image); + _subimage = QSize(); } void Image::bind(QOpenGLFunctions &f) { @@ -119,8 +120,10 @@ void Image::bind(QOpenGLFunctions &f) { } void Image::destroy(QOpenGLFunctions *f) { + invalidate(); _textures.destroy(f); _cacheKey = 0; + _textureSize = QSize(); } TexturedRect Image::texturedRect( diff --git a/ui/gl/gl_shader.cpp b/ui/gl/gl_shader.cpp index 2f47edd..f306bbe 100644 --- a/ui/gl/gl_shader.cpp +++ b/ui/gl/gl_shader.cpp @@ -80,6 +80,16 @@ uniform sampler2D s_texture; }; } +QString FragmentYUV2RGB() { + return R"( + result = vec4( + 1.164 * y + 1.596 * v, + 1.164 * y - 0.392 * u - 0.813 * v, + 1.164 * y + 2.17 * u, + 1.); +)"; +} + ShaderPart FragmentSampleYUV420Texture() { return { .header = R"( @@ -92,12 +102,23 @@ uniform sampler2D v_texture; float y = texture2D(y_texture, v_texcoord).a - 0.0625; float u = texture2D(u_texture, v_texcoord).a - 0.5; float v = texture2D(v_texture, v_texcoord).a - 0.5; - result = vec4( - 1.164 * y + 1.596 * v, - 1.164 * y - 0.392 * u - 0.813 * v, - 1.164 * y + 2.17 * u, - 1.); +)" + FragmentYUV2RGB(), + }; +} + +ShaderPart FragmentSampleNV12Texture() { + return { + .header = R"( +varying vec2 v_texcoord; +uniform sampler2D y_texture; +uniform sampler2D uv_texture; )", + .body = R"( + float y = texture2D(y_texture, v_texcoord).a - 0.0625; + vec2 uv = texture2D(uv_texture, v_texcoord).rg - vec2(0.5, 0.5); + float u = uv.x; + float v = uv.y; +)" + FragmentYUV2RGB(), }; } @@ -178,9 +199,9 @@ not_null MakeShader( const QString &source) { const auto result = new QOpenGLShader(type, program); if (!result->compileSourceCode(source)) { - LOG(("Shader Compilation Failed: %1, error %2." - ).arg(source - ).arg(result->log())); + LOG(("Shader Compilation Failed: %1, error %2.").arg( + source, + result->log())); } program->addShader(result); return result; diff --git a/ui/gl/gl_shader.h b/ui/gl/gl_shader.h index 5dce379..521b311 100644 --- a/ui/gl/gl_shader.h +++ b/ui/gl/gl_shader.h @@ -24,6 +24,7 @@ struct ShaderPart { [[nodiscard]] ShaderPart VertexPassTextureCoord(char prefix = 'v'); [[nodiscard]] ShaderPart FragmentSampleARGB32Texture(); [[nodiscard]] ShaderPart FragmentSampleYUV420Texture(); +[[nodiscard]] ShaderPart FragmentSampleNV12Texture(); [[nodiscard]] ShaderPart FragmentGlobalOpacity(); [[nodiscard]] ShaderPart VertexViewportTransform(); [[nodiscard]] ShaderPart FragmentRoundCorners(); diff --git a/ui/gl/gl_surface.cpp b/ui/gl/gl_surface.cpp index fc45dd6..bc25970 100644 --- a/ui/gl/gl_surface.cpp +++ b/ui/gl/gl_surface.cpp @@ -9,10 +9,10 @@ #include "ui/rp_widget.h" #include "ui/painter.h" +#include #include #include #include -#include #include namespace Ui::GL { @@ -32,10 +32,13 @@ private: void initializeGL() override; void resizeGL(int w, int h) override; void paintEvent(QPaintEvent *e) override; + void paintGL() override; + bool eventHook(QEvent *e) override; void callDeInit(); const std::unique_ptr _renderer; QMetaObject::Connection _connection; + QSize _deviceSize; }; @@ -55,6 +58,7 @@ SurfaceOpenGL::SurfaceOpenGL( std::unique_ptr renderer) : RpWidgetBase(parent) , _renderer(std::move(renderer)) { + setUpdateBehavior(QOpenGLWidget::PartialUpdate); } SurfaceOpenGL::~SurfaceOpenGL() { @@ -76,33 +80,36 @@ void SurfaceOpenGL::initializeGL() { } void SurfaceOpenGL::resizeGL(int w, int h) { + _deviceSize = QSize(w, h) * devicePixelRatio(); _renderer->resize(this, *context()->functions(), w, h); } void SurfaceOpenGL::paintEvent(QPaintEvent *e) { + if (_deviceSize != size() * devicePixelRatio()) { + QCoreApplication::postEvent(this, new QResizeEvent(size(), size())); + } + QOpenGLWidget::paintEvent(e); +} + +void SurfaceOpenGL::paintGL() { if (!updatesEnabled() || size().isEmpty() || !isValid()) { return; } - auto redirectOffset = QPoint(); - const auto rpd = redirected(&redirectOffset); - const auto device = rpd ? rpd : static_cast(this); - const auto engine = device->paintEngine(); - if (!engine) { - return; - } - engine->begin(device); - if (!isValid()) { // The call above could lose the context. - return; - } const auto f = context()->functions(); if (const auto bg = _renderer->clearColor()) { f->glClearColor(bg->redF(), bg->greenF(), bg->blueF(), bg->alphaF()); f->glClear(GL_COLOR_BUFFER_BIT); } f->glDisable(GL_BLEND); - f->glViewport(0, 0, device->width(), device->height()); _renderer->paint(this, *f); - engine->end(); +} + +bool SurfaceOpenGL::eventHook(QEvent *e) { + const auto result = RpWidgetBase::eventHook(e); + if (e->type() == QEvent::ScreenChangeInternal) { + _deviceSize = size() * devicePixelRatio(); + } + return result; } void SurfaceOpenGL::callDeInit() { diff --git a/ui/gl/gl_window.cpp b/ui/gl/gl_window.cpp index f2cc816..0f3fdd1 100644 --- a/ui/gl/gl_window.cpp +++ b/ui/gl/gl_window.cpp @@ -24,11 +24,42 @@ namespace { constexpr auto kUseNativeChild = false;// ::Platform::IsWindows(); +class RpWidgetOpenGL : public RpWidget { +protected: +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + std::optional rhiConfig() const override { + return { QPlatformBackingStoreRhiConfig::OpenGL }; + } +#endif // Qt >= 6.4.0 +}; + +class RpWindowOpenGL : public RpWindow { +protected: +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + std::optional rhiConfig() const override { + return { QPlatformBackingStoreRhiConfig::OpenGL }; + } +#endif // Qt >= 6.4.0 +}; + +[[nodiscard]] Fn ChooseBackendWrap( + Fn chooseBackend) { + return [=](Capabilities capabilities) { + const auto backend = chooseBackend(capabilities); + const auto use = backend == Backend::OpenGL; + LOG(("OpenGL: %1 (Window)").arg(use ? "[TRUE]" : "[FALSE]")); + return backend; + }; +} + } // namespace -Window::Window() -: _window(createWindow()) -, _bodyNativeWrap(createNativeBodyWrap()) +Window::Window() : Window(ChooseBackendDefault) { +} + +Window::Window(Fn chooseBackend) +: _window(createWindow(ChooseBackendWrap(chooseBackend))) +, _bodyNativeWrap(createNativeBodyWrap(ChooseBackendWrap(chooseBackend))) , _body(_bodyNativeWrap ? _bodyNativeWrap.get() : _window->body().get()) { } @@ -46,19 +77,12 @@ not_null Window::widget() const { return _body.get(); } -std::unique_ptr Window::createWindow() { - auto result = std::make_unique(); +std::unique_ptr Window::createWindow( + const Fn &chooseBackend) { + std::unique_ptr result = std::make_unique(); if constexpr (!kUseNativeChild) { - const auto capabilities = CheckCapabilities(result.get()); - const auto use = ::Platform::IsMac() - ? true - : ::Platform::IsWindows() - ? capabilities.supported - : capabilities.transparency; - LOG(("OpenGL: %1 (Window)").arg(use ? "[TRUE]" : "[FALSE]")); - _backend = use ? Backend::OpenGL : Backend::Raster; - - if (!use) { + _backend = chooseBackend(CheckCapabilities(result.get())); + if (_backend != Backend::OpenGL) { // We have to create a new window, if OpenGL initialization failed. result = std::make_unique(); } @@ -66,12 +90,13 @@ std::unique_ptr Window::createWindow() { return result; } -std::unique_ptr Window::createNativeBodyWrap() { +std::unique_ptr Window::createNativeBodyWrap( + const Fn &chooseBackend) { if constexpr (!kUseNativeChild) { return nullptr; } const auto create = [] { - auto result = std::make_unique(); + auto result = std::make_unique(); result->setWindowFlags(Qt::FramelessWindowHint | Qt::Window); result->setAttribute(Qt::WA_NativeWindow); result->setAttribute(Qt::WA_DontCreateNativeAncestors); @@ -81,16 +106,8 @@ std::unique_ptr Window::createNativeBodyWrap() { }; auto result = create(); - const auto capabilities = CheckCapabilities(result.get()); - const auto use = ::Platform::IsMac() - ? true - : ::Platform::IsWindows() - ? capabilities.supported - : capabilities.transparency; - LOG(("OpenGL: %1 (WindowBody)").arg(use ? "[TRUE]" : "[FALSE]")); - _backend = use ? Backend::OpenGL : Backend::Raster; - - if (!use) { + _backend = chooseBackend(CheckCapabilities(result.get())); + if (_backend != Backend::OpenGL) { // We have to create a new window, if OpenGL initialization failed. result = create(); } diff --git a/ui/gl/gl_window.h b/ui/gl/gl_window.h index 797fcdf..2e92448 100644 --- a/ui/gl/gl_window.h +++ b/ui/gl/gl_window.h @@ -6,7 +6,6 @@ // #pragma once - namespace Ui { class RpWindow; class RpWidget; @@ -15,10 +14,12 @@ class RpWidget; namespace Ui::GL { enum class Backend; +struct Capabilities; class Window final { public: Window(); + explicit Window(Fn chooseBackend); ~Window(); [[nodiscard]] Backend backend() const; @@ -26,8 +27,10 @@ public: [[nodiscard]] not_null widget() const; private: - [[nodiscard]] std::unique_ptr createWindow(); - [[nodiscard]] std::unique_ptr createNativeBodyWrap(); + [[nodiscard]] std::unique_ptr createWindow( + const Fn &chooseBackend); + [[nodiscard]] std::unique_ptr createNativeBodyWrap( + const Fn &chooseBackend); Backend _backend = Backend(); const std::unique_ptr _window; diff --git a/ui/image/image_prepare.cpp b/ui/image/image_prepare.cpp index da8bc33..12a80ef 100644 --- a/ui/image/image_prepare.cpp +++ b/ui/image/image_prepare.cpp @@ -15,13 +15,15 @@ #include "styles/palette.h" #include "styles/style_basic.h" -#include "zlib.h" +#include #include #include #include #include #include +#include + namespace Images { namespace { @@ -35,7 +37,7 @@ TG_FORCE_INLINE uint64 BlurGetColors(const uchar *p) { + ((uint64)p[3] << 48); } -const QImage &CircleMask(QSize size) { +const QImage &EllipseMaskCached(QSize size) { const auto key = (uint64(uint32(size.width())) << 32) | uint64(uint32(size.height())); @@ -48,17 +50,7 @@ const QImage &CircleMask(QSize size) { } lock.unlock(); - auto mask = QImage( - size, - QImage::Format_ARGB32_Premultiplied); - mask.fill(Qt::transparent); - { - QPainter p(&mask); - PainterHighQualityEnabler hq(p); - p.setBrush(Qt::white); - p.setPen(Qt::NoPen); - p.drawEllipse(QRect(QPoint(), size)); - } + auto mask = EllipseMask(size, 1.); lock.relock(); return Masks.emplace(key, std::move(mask)).first->second; @@ -329,6 +321,22 @@ std::array CornersMask(int radius) { return PrepareCornersMask(radius); } +QImage EllipseMask(QSize size, double ratio) { + size *= ratio; + auto result = QImage(size, QImage::Format_ARGB32_Premultiplied); + result.fill(Qt::transparent); + + QPainter p(&result); + PainterHighQualityEnabler hq(p); + p.setBrush(Qt::white); + p.setPen(Qt::NoPen); + p.drawEllipse(QRect(QPoint(), size)); + p.end(); + + result.setDevicePixelRatio(ratio); + return result; +} + std::array PrepareCorners( int radius, const style::color &color) { @@ -420,12 +428,12 @@ std::array PrepareCorners( return {}; } auto result = ReadResult(); + result.format = reader.format().toLower(); + result.animated = reader.supportsAnimation() + && (reader.imageCount() > 1); if (!reader.read(&result.image) || result.image.isNull()) { return {}; } - result.animated = reader.supportsAnimation() - && (reader.imageCount() > 1); - result.format = reader.format().toLower(); return result; } @@ -459,9 +467,7 @@ ReadResult Read(ReadArgs &&args) { Qt::KeepAspectRatio, Qt::SmoothTransformation); } - if (args.forceOpaque - && result.format != qstr("jpg") - && result.format != qstr("jpeg")) { + if (args.forceOpaque && result.format != qstr("jpeg")) { result.image = Opaque(std::move(result.image)); } return result; @@ -492,7 +498,7 @@ ReadResult Read(ReadArgs &&args) { : Option::None); } -QImage Blur(QImage &&image) { +QImage Blur(QImage &&image, bool ignoreAlpha) { if (image.isNull()) { return std::move(image); } @@ -518,7 +524,7 @@ QImage Blur(QImage &&image) { if (radius >= 16 || div >= w || div >= h || stride > w * 4) { return std::move(image); } - const auto withalpha = image.hasAlphaChannel(); + const auto withalpha = !ignoreAlpha && image.hasAlphaChannel(); if (withalpha) { auto smaller = QImage(image.size(), image.format()); { @@ -973,7 +979,7 @@ QImage Circle(QImage &&image, QRect target) { Expects(!image.isNull()); if (target.isNull()) { - target = QRect(QPoint(), image.size()); + target = QRect(QPoint( ), image.size()); } else { Assert(QRect(QPoint(), image.size()).contains(target)); } @@ -987,72 +993,99 @@ QImage Circle(QImage &&image, QRect target) { p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.drawImage( QRectF(target.topLeft() / ratio, target.size() / ratio), - CircleMask(target.size())); + EllipseMaskCached(target.size())); p.end(); return std::move(image); } +QImage Round( + QImage &&image, + CornersMaskRef mask, + QRect target) { + if (target.isNull()) { + target = QRect(QPoint(), image.size()); + } else { + Assert(QRect(QPoint(), image.size()).contains(target)); + } + const auto targetWidth = target.width(); + const auto targetHeight = target.height(); + + image = std::move(image).convertToFormat( + QImage::Format_ARGB32_Premultiplied); + Assert(!image.isNull()); + + // We need to detach image first (if it is shared), before we + // count some offsets using QImage::bytesPerLine etc, because + // bytesPerLine may change on detach, this leads to crashes: + // Real image bytesPerLine is smaller than the one we use for offsets. + auto ints = reinterpret_cast(image.bits()); + + constexpr auto kImageIntsPerPixel = 1; + const auto imageIntsPerLine = (image.bytesPerLine() >> 2); + Assert(image.depth() == ((kImageIntsPerPixel * sizeof(uint32)) << 3)); + Assert(image.bytesPerLine() == (imageIntsPerLine << 2)); + const auto maskCorner = [&]( + const QImage *mask, + bool right = false, + bool bottom = false) { + const auto maskWidth = mask ? mask->width() : 0; + const auto maskHeight = mask ? mask->height() : 0; + if (!maskWidth + || !maskHeight + || targetWidth < maskWidth + || targetHeight < maskHeight) { + return; + } + + const auto maskBytesPerPixel = (mask->depth() >> 3); + const auto maskBytesPerLine = mask->bytesPerLine(); + const auto maskBytesAdded = maskBytesPerLine + - maskWidth * maskBytesPerPixel; + Assert(maskBytesAdded >= 0); + Assert(mask->depth() == (maskBytesPerPixel << 3)); + const auto imageIntsAdded = imageIntsPerLine + - maskWidth * kImageIntsPerPixel; + Assert(imageIntsAdded >= 0); + auto imageInts = ints + target.x() + target.y() * imageIntsPerLine; + if (right) { + imageInts += targetWidth - maskWidth; + } + if (bottom) { + imageInts += (targetHeight - maskHeight) * imageIntsPerLine; + } + auto maskBytes = mask->constBits(); + for (auto y = 0; y != maskHeight; ++y) { + for (auto x = 0; x != maskWidth; ++x) { + auto opacity = static_cast(*maskBytes) + 1; + *imageInts = anim::unshifted(anim::shifted(*imageInts) * opacity); + maskBytes += maskBytesPerPixel; + imageInts += kImageIntsPerPixel; + } + maskBytes += maskBytesAdded; + imageInts += imageIntsAdded; + } + }; + + maskCorner(mask.p[0]); + maskCorner(mask.p[1], true); + maskCorner(mask.p[2], false, true); + maskCorner(mask.p[3], true, true); + + return std::move(image); +} + QImage Round( QImage &&image, gsl::span cornerMasks, RectParts corners, QRect target) { - if (target.isNull()) { - target = QRect(QPoint(), image.size()); - } else { - Assert(QRect(QPoint(), image.size()).contains(target)); - } - auto cornerWidth = cornerMasks[0].width(); - auto cornerHeight = cornerMasks[0].height(); - auto targetWidth = target.width(); - auto targetHeight = target.height(); - if (targetWidth < cornerWidth || targetHeight < cornerHeight) { - return std::move(image); - } - - // We need to detach image first (if it is shared), before we - // count some offsets using QImage::bytesPerLine etc, because - // bytesPerLine may change on detach, this leads to crashes: - // Real image bytesPerLine is smaller than the one we use for offsets. - auto ints = reinterpret_cast(image.bits()); - - constexpr auto imageIntsPerPixel = 1; - auto imageIntsPerLine = (image.bytesPerLine() >> 2); - Assert(image.depth() == static_cast((imageIntsPerPixel * sizeof(uint32)) << 3)); - Assert(image.bytesPerLine() == (imageIntsPerLine << 2)); - auto intsTopLeft = ints + target.x() + target.y() * imageIntsPerLine; - auto intsTopRight = ints + target.x() + targetWidth - cornerWidth + target.y() * imageIntsPerLine; - auto intsBottomLeft = ints + target.x() + (target.y() + targetHeight - cornerHeight) * imageIntsPerLine; - auto intsBottomRight = ints + target.x() + targetWidth - cornerWidth + (target.y() + targetHeight - cornerHeight) * imageIntsPerLine; - auto maskCorner = [&](uint32 *imageInts, const QImage &mask) { - auto maskWidth = mask.width(); - auto maskHeight = mask.height(); - auto maskBytesPerPixel = (mask.depth() >> 3); - auto maskBytesPerLine = mask.bytesPerLine(); - auto maskBytesAdded = maskBytesPerLine - maskWidth * maskBytesPerPixel; - auto maskBytes = mask.constBits(); - Assert(maskBytesAdded >= 0); - Assert(mask.depth() == (maskBytesPerPixel << 3)); - auto imageIntsAdded = imageIntsPerLine - maskWidth * imageIntsPerPixel; - Assert(imageIntsAdded >= 0); - for (auto y = 0; y != maskHeight; ++y) { - for (auto x = 0; x != maskWidth; ++x) { - auto opacity = static_cast(*maskBytes) + 1; - *imageInts = anim::unshifted(anim::shifted(*imageInts) * opacity); - maskBytes += maskBytesPerPixel; - imageInts += imageIntsPerPixel; - } - maskBytes += maskBytesAdded; - imageInts += imageIntsAdded; - } - }; - if (corners & RectPart::TopLeft) maskCorner(intsTopLeft, cornerMasks[0]); - if (corners & RectPart::TopRight) maskCorner(intsTopRight, cornerMasks[1]); - if (corners & RectPart::BottomLeft) maskCorner(intsBottomLeft, cornerMasks[2]); - if (corners & RectPart::BottomRight) maskCorner(intsBottomRight, cornerMasks[3]); - - return std::move(image); + return Round(std::move(image), CornersMaskRef({ + (corners & RectPart::TopLeft) ? &cornerMasks[0] : nullptr, + (corners & RectPart::TopRight) ? &cornerMasks[1] : nullptr, + (corners & RectPart::BottomLeft) ? &cornerMasks[2] : nullptr, + (corners & RectPart::BottomRight) ? &cornerMasks[3] : nullptr, + }), target); } QImage Round( @@ -1068,10 +1101,6 @@ QImage Round( } Assert(!image.isNull()); - image = std::move(image).convertToFormat( - QImage::Format_ARGB32_Premultiplied); - Assert(!image.isNull()); - const auto masks = CornersMask(radius); return Round(std::move(image), masks, corners, target); } @@ -1110,23 +1139,23 @@ QImage Colored(QImage &&image, QColor add) { } if (const auto pix = image.bits()) { - const auto ca = int(add.alphaF() * 0xFF); - const auto cr = int(add.redF() * 0xFF); - const auto cg = int(add.greenF() * 0xFF); - const auto cb = int(add .blueF() * 0xFF); + const auto ca = add.alpha(); + const auto cr = add.red() * (ca + 1); + const auto cg = add.green() * (ca + 1); + const auto cb = add.blue() * (ca + 1); + const auto ra = (0x100 - ca) * 0x100; const auto w = image.width(); const auto h = image.height(); - const auto size = w * h * 4; - for (auto i = index_type(); i != size; i += 4) { - const auto b = pix[i]; - const auto g = pix[i + 1]; - const auto r = pix[i + 2]; - const auto a = pix[i + 3]; - const auto aca = a * ca; - pix[i + 0] = uchar(b + ((aca * (cb - b)) >> 16)); - pix[i + 1] = uchar(g + ((aca * (cg - g)) >> 16)); - pix[i + 2] = uchar(r + ((aca * (cr - r)) >> 16)); - pix[i + 3] = uchar(a + ((aca * (0xFF - a)) >> 16)); + const auto add = image.bytesPerLine() - (w * 4); + auto i = index_type(); + for (auto y = 0; y != h; ++y) { + for (auto to = i + (w * 4); i != to; i += 4) { + const auto a = pix[i + 3] + 1; + pix[i + 0] = (ra * pix[i + 0] + a * cb) >> 16; + pix[i + 1] = (ra * pix[i + 1] + a * cg) >> 16; + pix[i + 2] = (ra * pix[i + 2] + a * cr) >> 16; + } + i += add; } } return std::move(image); @@ -1221,4 +1250,374 @@ QImage Prepare(QImage image, int w, int h, const PrepareArgs &args) { return image; } +bool IsProgressiveJpeg(const QByteArray &bytes) { + try { + struct jpeg_decompress_struct info; + struct jpeg_error_mgr jerr; + + info.err = jpeg_std_error(&jerr); + jerr.error_exit = [](j_common_ptr cinfo) { + (*cinfo->err->output_message)(cinfo); + throw std::exception(); + }; + + jpeg_create_decompress(&info); + const auto guard = gsl::finally([&] { + jpeg_destroy_decompress(&info); + }); + + jpeg_mem_src( + &info, + reinterpret_cast(bytes.data()), + bytes.size()); + if (jpeg_read_header(&info, TRUE) != 1) { + return false; + } + + return (info.progressive_mode > 0); + } catch (...) { + return false; + } +} + +QByteArray MakeProgressiveJpeg(const QByteArray &bytes) { + try { + struct jpeg_decompress_struct srcinfo; + struct jpeg_compress_struct dstinfo; + struct jpeg_error_mgr jerr; + + srcinfo.err = jpeg_std_error(&jerr); + dstinfo.err = jpeg_std_error(&jerr); + jerr.error_exit = [](j_common_ptr cinfo) { + (*cinfo->err->output_message)(cinfo); + throw std::exception(); + }; + + jpeg_create_decompress(&srcinfo); + const auto srcguard = gsl::finally([&] { + jpeg_abort_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + }); + + jpeg_create_compress(&dstinfo); + const auto dstguard = gsl::finally([&] { + jpeg_abort_compress(&dstinfo); + jpeg_destroy_compress(&dstinfo); + }); + + jpeg_mem_src( + &srcinfo, + reinterpret_cast(bytes.data()), + bytes.size()); + + jpeg_save_markers(&srcinfo, JPEG_COM, 0xFFFF); + for (int m = 0; m < 16; m++) { + jpeg_save_markers(&srcinfo, JPEG_APP0 + m, 0xFFFF); + } + + jpeg_read_header(&srcinfo, true); + const auto coefArrays = jpeg_read_coefficients(&srcinfo); + jpeg_copy_critical_parameters(&srcinfo, &dstinfo); + jpeg_simple_progression(&dstinfo); + + unsigned char* outbuffer = nullptr; + long unsigned int outsize = 0; + jpeg_mem_dest(&dstinfo, &outbuffer, &outsize); + const auto outbufferGuard = gsl::finally([&] { + free(outbuffer); + }); + + jpeg_write_coefficients(&dstinfo, coefArrays); + + for (jpeg_saved_marker_ptr marker = srcinfo.marker_list + ; marker != nullptr + ; marker = marker->next) { + if (dstinfo.write_JFIF_header + && marker->marker == JPEG_APP0 + && marker->data_length >= 5 + && marker->data[0] == 0x4A + && marker->data[1] == 0x46 + && marker->data[2] == 0x49 + && marker->data[3] == 0x46 + && marker->data[4] == 0) + continue; // reject duplicate JFIF + if (dstinfo.write_Adobe_marker + && marker->marker == JPEG_APP0 + 14 + && marker->data_length >= 5 + && marker->data[0] == 0x41 + && marker->data[1] == 0x64 + && marker->data[2] == 0x6F + && marker->data[3] == 0x62 + && marker->data[4] == 0x65) + continue; // reject duplicate Adobe + jpeg_write_marker( + &dstinfo, + marker->marker, + marker->data, + marker->data_length); + } + + jpeg_finish_compress(&dstinfo); + jpeg_finish_decompress(&srcinfo); + + return QByteArray(reinterpret_cast(outbuffer), outsize); + } catch (...) { + return {}; + } +} + +QByteArray ExpandInlineBytes(const QByteArray &bytes) { + if (bytes.size() < 3 || bytes[0] != '\x01') { + return QByteArray(); + } + const char header[] = "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49" + "\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x28\x1c" + "\x1e\x23\x1e\x19\x28\x23\x21\x23\x2d\x2b\x28\x30\x3c\x64\x41\x3c\x37\x37" + "\x3c\x7b\x58\x5d\x49\x64\x91\x80\x99\x96\x8f\x80\x8c\x8a\xa0\xb4\xe6\xc3" + "\xa0\xaa\xda\xad\x8a\x8c\xc8\xff\xcb\xda\xee\xf5\xff\xff\xff\x9b\xc1\xff" + "\xff\xff\xfa\xff\xe6\xfd\xff\xf8\xff\xdb\x00\x43\x01\x2b\x2d\x2d\x3c\x35" + "\x3c\x76\x41\x41\x76\xf8\xa5\x8c\xa5\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8" + "\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8" + "\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8" + "\xf8\xf8\xf8\xf8\xf8\xff\xc0\x00\x11\x08\x00\x00\x00\x00\x03\x01\x22\x00" + "\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01" + "\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05" + "\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06" + "\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52" + "\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28" + "\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53" + "\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75" + "\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96" + "\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" + "\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6" + "\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4" + "\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05" + "\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41" + "\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33" + "\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26" + "\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a" + "\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74" + "\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94" + "\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4" + "\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4" + "\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4" + "\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00" + "\x3f\x00"; + const char footer[] = "\xff\xd9"; + auto real = QByteArray(header, sizeof(header) - 1); + real[164] = bytes[1]; + real[166] = bytes[2]; + return real + + bytes.mid(3) + + QByteArray::fromRawData(footer, sizeof(footer) - 1); +} + +QImage FromInlineBytes(const QByteArray &bytes) { + return Read({ .content = ExpandInlineBytes(bytes) }).image; +} + +// Thanks TDLib for code. +QByteArray ExpandPathInlineBytes(const QByteArray &bytes) { + auto result = QByteArray(); + result.reserve(3 * (bytes.size() + 1)); + result.append('M'); + for (unsigned char c : bytes) { + if (c >= 128 + 64) { + result.append("AACAAAAHAAALMAAAQASTAVAAAZ" + "aacaaaahaaalmaaaqastava.az0123456789-,"[c - 128 - 64]); + } else { + if (c >= 128) { + result.append(','); + } else if (c >= 64) { + result.append('-'); + } + //char buffer[3] = { 0 }; // Unavailable on macOS < 10.15. + //std::to_chars(buffer, buffer + 3, (c & 63)); + //result.append(buffer); + result.append(QByteArray::number(c & 63)); + } + } + result.append('z'); + return result; +} + +QPainterPath PathFromInlineBytes(const QByteArray &bytes) { + if (bytes.isEmpty()) { + return QPainterPath(); + } + const auto expanded = ExpandPathInlineBytes(bytes); + const auto path = expanded.data(); // Allows checking for '\0' by index. + auto position = 0; + + const auto isAlpha = [](char c) { + c |= 0x20; + return 'a' <= c && c <= 'z'; + }; + const auto isDigit = [](char c) { + return '0' <= c && c <= '9'; + }; + const auto skipCommas = [&] { + while (path[position] == ',') { + ++position; + } + }; + const auto getNumber = [&] { + skipCommas(); + auto sign = 1; + if (path[position] == '-') { + sign = -1; + ++position; + } + double res = 0; + while (isDigit(path[position])) { + res = res * 10 + path[position++] - '0'; + } + if (path[position] == '.') { + ++position; + double mul = 0.1; + while (isDigit(path[position])) { + res += (path[position] - '0') * mul; + mul *= 0.1; + ++position; + } + } + return sign * res; + }; + + auto result = QPainterPath(); + auto x = 0.; + auto y = 0.; + while (path[position] != '\0') { + skipCommas(); + if (path[position] == '\0') { + break; + } + + while (path[position] == 'm' || path[position] == 'M') { + auto command = path[position++]; + do { + if (command == 'm') { + x += getNumber(); + y += getNumber(); + } else { + x = getNumber(); + y = getNumber(); + } + skipCommas(); + } while (path[position] != '\0' && !isAlpha(path[position])); + } + + auto xStart = x; + auto yStart = y; + result.moveTo(xStart, yStart); + auto haveLastEndControlPoint = false; + auto xLastEndControlPoint = 0.; + auto yLastEndControlPoint = 0.; + auto isClosed = false; + auto command = '-'; + while (!isClosed) { + skipCommas(); + if (path[position] == '\0') { + LOG(("SVG Error: Receive unclosed path: %1" + ).arg(QString::fromLatin1(path))); + return QPainterPath(); + } + if (isAlpha(path[position])) { + command = path[position++]; + } + switch (command) { + case 'l': + case 'L': + case 'h': + case 'H': + case 'v': + case 'V': + if (command == 'l' || command == 'h') { + x += getNumber(); + } else if (command == 'L' || command == 'H') { + x = getNumber(); + } + if (command == 'l' || command == 'v') { + y += getNumber(); + } else if (command == 'L' || command == 'V') { + y = getNumber(); + } + result.lineTo(x, y); + haveLastEndControlPoint = false; + break; + case 'C': + case 'c': + case 'S': + case 's': { + auto xStartControlPoint = 0.; + auto yStartControlPoint = 0.; + if (command == 'S' || command == 's') { + if (haveLastEndControlPoint) { + xStartControlPoint = 2 * x - xLastEndControlPoint; + yStartControlPoint = 2 * y - yLastEndControlPoint; + } else { + xStartControlPoint = x; + yStartControlPoint = y; + } + } else { + xStartControlPoint = getNumber(); + yStartControlPoint = getNumber(); + if (command == 'c') { + xStartControlPoint += x; + yStartControlPoint += y; + } + } + + xLastEndControlPoint = getNumber(); + yLastEndControlPoint = getNumber(); + if (command == 'c' || command == 's') { + xLastEndControlPoint += x; + yLastEndControlPoint += y; + } + haveLastEndControlPoint = true; + + if (command == 'c' || command == 's') { + x += getNumber(); + y += getNumber(); + } else { + x = getNumber(); + y = getNumber(); + } + result.cubicTo( + xStartControlPoint, + yStartControlPoint, + xLastEndControlPoint, + yLastEndControlPoint, + x, + y); + break; + } + case 'm': + case 'M': + --position; + [[fallthrough]]; + case 'z': + case 'Z': + if (x != xStart || y != yStart) { + x = xStart; + y = yStart; + result.lineTo(x, y); + } + isClosed = true; + break; + default: + LOG(("SVG Error: Receive invalid command %1 at pos %2: %3" + ).arg(command + ).arg(position + ).arg(QString::fromLatin1(path))); + return QPainterPath(); + } + } + } + return result; +} + } // namespace Images diff --git a/ui/image/image_prepare.h b/ui/image/image_prepare.h index 3535c79..6368c0e 100644 --- a/ui/image/image_prepare.h +++ b/ui/image/image_prepare.h @@ -46,6 +46,49 @@ namespace Images { int bottomAlpha, QColor color = QColor(0, 0, 0)); +inline constexpr auto kTopLeft = 0; +inline constexpr auto kTopRight = 1; +inline constexpr auto kBottomLeft = 2; +inline constexpr auto kBottomRight = 3; + +struct CornersMaskRef { + CornersMaskRef() = default; + explicit CornersMaskRef(gsl::span masks) + : p{ &masks[0], &masks[1], &masks[2], &masks[3] } { + } + explicit CornersMaskRef(std::array masks) + : p{ &masks[0], &masks[1], &masks[2], &masks[3] } { + } + explicit CornersMaskRef(gsl::span masks) + : p{ masks[0], masks[1], masks[2], masks[3] } { + } + explicit CornersMaskRef(std::array masks) + : p{ masks[0], masks[1], masks[2], masks[3] } { + } + + [[nodiscard]] bool empty() const { + return !p[0] && !p[1] && !p[2] && !p[3]; + } + + std::array p{}; + + friend inline constexpr std::strong_ordering operator<=>( + CornersMaskRef a, + CornersMaskRef b) noexcept { + for (auto i = 0; i != 4; ++i) { + if (a.p[i] < b.p[i]) { + return std::strong_ordering::less; + } else if (a.p[i] > b.p[i]) { + return std::strong_ordering::greater; + } + } + return std::strong_ordering::equal; + } + friend inline constexpr bool operator==( + CornersMaskRef a, + CornersMaskRef b) noexcept = default; +}; + [[nodiscard]] const std::array &CornersMask( ImageRoundRadius radius); [[nodiscard]] std::array PrepareCorners( @@ -53,6 +96,8 @@ namespace Images { const style::color &color); [[nodiscard]] std::array CornersMask(int radius); +[[nodiscard]] QImage EllipseMask(QSize size, double ratio = style::DevicePixelRatio()); + [[nodiscard]] std::array PrepareCorners( int radius, const style::color &color); @@ -100,7 +145,12 @@ inline constexpr auto is_flag_type(Option) { return true; }; ImageRoundRadius radius, RectParts corners = RectPart::AllCorners); -[[nodiscard]] QImage Blur(QImage &&image); +[[nodiscard]] QImage Round( + QImage &&image, + CornersMaskRef mask, + QRect target = QRect()); + +[[nodiscard]] QImage Blur(QImage &&image, bool ignoreAlpha = false); [[nodiscard]] QImage Round( QImage &&image, ImageRoundRadius radius, @@ -153,4 +203,11 @@ struct PrepareArgs { return Prepare(std::move(image), size.width(), size.height(), args); } +[[nodiscard]] bool IsProgressiveJpeg(const QByteArray &bytes); +[[nodiscard]] QByteArray MakeProgressiveJpeg(const QByteArray &bytes); + +[[nodiscard]] QByteArray ExpandInlineBytes(const QByteArray &bytes); +[[nodiscard]] QImage FromInlineBytes(const QByteArray &bytes); +[[nodiscard]] QPainterPath PathFromInlineBytes(const QByteArray &bytes); + } // namespace Images diff --git a/ui/integration.cpp b/ui/integration.cpp index fc0ca14..f249c18 100644 --- a/ui/integration.cpp +++ b/ui/integration.cpp @@ -9,6 +9,8 @@ #include "ui/style/style_core_custom_font.h" #include "ui/gl/gl_detection.h" #include "ui/text/text_entity.h" +#include "ui/text/text_block.h" +#include "ui/toast/toast.h" #include "ui/basic_click_handlers.h" #include "base/platform/base_platform_info.h" @@ -51,10 +53,6 @@ bool Integration::screenIsLocked() { return false; } -QString Integration::timeFormat() { - return u"hh:mm"_q; -} - std::shared_ptr Integration::createLinkHandler( const EntityLinkData &data, const std::any &context) { @@ -74,12 +72,33 @@ std::shared_ptr Integration::createLinkHandler( return nullptr; } +std::unique_ptr Integration::createCustomEmoji( + const QString &data, + const std::any &context) { + return nullptr; +} + +Fn Integration::createSpoilerRepaint(const std::any &context) { + return nullptr; +} + +bool Integration::allowClickHandlerActivation( + const std::shared_ptr &handler, + const ClickContext &context) { + return true; +} + bool Integration::handleUrlClick( const QString &url, const QVariant &context) { return false; } +bool Integration::copyPreOnClick(const QVariant &context) { + Toast::Show(u"Code copied to clipboard."_q); + return true; +} + QString Integration::convertTagToMimeTag(const QString &tagId) { return tagId; } @@ -140,6 +159,10 @@ QString Integration::phraseFormattingStrikeOut() { return "Strike-through"; } +QString Integration::phraseFormattingBlockquote() { + return "Quote"; +} + QString Integration::phraseFormattingMonospace() { return "Monospace"; } @@ -148,4 +171,56 @@ QString Integration::phraseFormattingSpoiler() { return "Spoiler"; } +QString Integration::phraseButtonOk() { + return "OK"; +} + +QString Integration::phraseButtonClose() { + return "Close"; +} + +QString Integration::phraseButtonCancel() { + return "Cancel"; +} + +QString Integration::phrasePanelCloseWarning() { + return "Warning"; +} + +QString Integration::phrasePanelCloseUnsaved() { + return "Changes that you made may not be saved."; +} + +QString Integration::phrasePanelCloseAnyway() { + return "Close anyway"; +} + +QString Integration::phraseBotSharePhone() { + return "Do you want to share your phone number with this bot?"; +} + +QString Integration::phraseBotSharePhoneTitle() { + return "Phone number"; +} + +QString Integration::phraseBotSharePhoneConfirm() { + return "Share"; +} + +QString Integration::phraseBotAllowWrite() { + return "Do you want to allow this bot to write you?"; +} + +QString Integration::phraseBotAllowWriteTitle() { + return "Allow write"; +} + +QString Integration::phraseBotAllowWriteConfirm() { + return "Allow"; +} + +QString Integration::phraseQuoteHeaderCopy() { + return "copy"; +} + } // namespace Ui diff --git a/ui/integration.h b/ui/integration.h index 07c9c56..7c39b0d 100644 --- a/ui/integration.h +++ b/ui/integration.h @@ -8,6 +8,8 @@ #include "base/basic_types.h" +#include + #include // Methods that must be implemented outside lib_ui. @@ -18,6 +20,7 @@ class QVariant; struct TextParseOptions; class ClickHandler; +struct ClickContext; struct EntityLinkData; namespace style { @@ -29,6 +32,10 @@ namespace Emoji { class One; } // namespace Emoji +namespace Text { +class CustomEmoji; +} // namespace Text + class Integration { public: static void Set(not_null instance); @@ -49,7 +56,6 @@ public: virtual style::CustomFontSettings fontSettings(); [[nodiscard]] virtual bool screenIsLocked(); - [[nodiscard]] virtual QString timeFormat(); [[nodiscard]] virtual std::shared_ptr createLinkHandler( const EntityLinkData &data, @@ -57,9 +63,18 @@ public: [[nodiscard]] virtual bool handleUrlClick( const QString &url, const QVariant &context); + [[nodiscard]] virtual bool copyPreOnClick(const QVariant &context); [[nodiscard]] virtual QString convertTagToMimeTag(const QString &tagId); [[nodiscard]] virtual const Emoji::One *defaultEmojiVariant( const Emoji::One *emoji); + [[nodiscard]] virtual auto createCustomEmoji( + const QString &data, + const std::any &context) -> std::unique_ptr; + [[nodiscard]] virtual Fn createSpoilerRepaint( + const std::any &context); + [[nodiscard]] virtual bool allowClickHandlerActivation( + const std::shared_ptr &handler, + const ClickContext &context); [[nodiscard]] virtual rpl::producer<> forcePopupMenuHideRequests(); @@ -75,8 +90,22 @@ public: [[nodiscard]] virtual QString phraseFormattingItalic(); [[nodiscard]] virtual QString phraseFormattingUnderline(); [[nodiscard]] virtual QString phraseFormattingStrikeOut(); + [[nodiscard]] virtual QString phraseFormattingBlockquote(); [[nodiscard]] virtual QString phraseFormattingMonospace(); [[nodiscard]] virtual QString phraseFormattingSpoiler(); + [[nodiscard]] virtual QString phraseButtonOk(); + [[nodiscard]] virtual QString phraseButtonClose(); + [[nodiscard]] virtual QString phraseButtonCancel(); + [[nodiscard]] virtual QString phrasePanelCloseWarning(); + [[nodiscard]] virtual QString phrasePanelCloseUnsaved(); + [[nodiscard]] virtual QString phrasePanelCloseAnyway(); + [[nodiscard]] virtual QString phraseBotSharePhone(); + [[nodiscard]] virtual QString phraseBotSharePhoneTitle(); + [[nodiscard]] virtual QString phraseBotSharePhoneConfirm(); + [[nodiscard]] virtual QString phraseBotAllowWrite(); + [[nodiscard]] virtual QString phraseBotAllowWriteTitle(); + [[nodiscard]] virtual QString phraseBotAllowWriteConfirm(); + [[nodiscard]] virtual QString phraseQuoteHeaderCopy(); }; diff --git a/ui/layers/box_content.cpp b/ui/layers/box_content.cpp index 18dd440..9ed0e96 100644 --- a/ui/layers/box_content.cpp +++ b/ui/layers/box_content.cpp @@ -18,14 +18,108 @@ #include "styles/style_layers.h" #include "styles/palette.h" -#include - namespace Ui { +namespace { + +class BoxShow final : public Show { +public: + explicit BoxShow(not_null box); + ~BoxShow(); + + void showOrHideBoxOrLayer( + std::variant< + v::null_t, + object_ptr, + std::unique_ptr> &&layer, + LayerOptions options, + anim::type animated) const override; + [[nodiscard]] not_null toastParent() const override; + [[nodiscard]] bool valid() const override; + operator bool() const override; + +private: + BoxShow(QPointer weak, ShowPtr wrapped); + + bool resolve() const; + + const QPointer _weak; + mutable std::shared_ptr _wrapped; + rpl::lifetime _lifetime; + +}; + +BoxShow::BoxShow(not_null box) +: BoxShow(MakeWeak(box.get()), nullptr) { +} + +BoxShow::BoxShow(QPointer weak, ShowPtr wrapped) +: _weak(weak) +, _wrapped(std::move(wrapped)) { + if (!resolve()) { + if (const auto box = _weak.data()) { + box->boxClosing( + ) | rpl::start_with_next([=] { + resolve(); + _lifetime.destroy(); + }, _lifetime); + } + } +} + +BoxShow::~BoxShow() = default; + +bool BoxShow::resolve() const { + if (_wrapped) { + return true; + } else if (const auto strong = _weak.data()) { + if (strong->hasDelegate()) { + _wrapped = strong->getDelegate()->showFactory()(); + return true; + } + } + return false; +} + +void BoxShow::showOrHideBoxOrLayer( + std::variant< + v::null_t, + object_ptr, + std::unique_ptr> &&layer, + LayerOptions options, + anim::type animated) const { + if (resolve()) { + _wrapped->showOrHideBoxOrLayer(std::move(layer), options, animated); + } +} + +not_null BoxShow::toastParent() const { + if (resolve()) { + return _wrapped->toastParent(); + } + Unexpected("Stale BoxShow::toastParent call."); +} + +bool BoxShow::valid() const { + return resolve() && _wrapped->valid(); +} + +BoxShow::operator bool() const { + return valid(); +} + +} // namespace void BoxContent::setTitle(rpl::producer title) { getDelegate()->setTitle(std::move(title) | Text::ToWithEntities()); } +QPointer BoxContent::addButton( + object_ptr button) { + auto result = QPointer(button.data()); + getDelegate()->addButton(std::move(button)); + return result; +} + QPointer BoxContent::addButton( rpl::producer text, Fn clickCallback) { @@ -35,20 +129,72 @@ QPointer BoxContent::addButton( getDelegate()->style().button); } +QPointer BoxContent::addButton( + rpl::producer text, + const style::RoundButton &st) { + return addButton(std::move(text), nullptr, st); +} + +QPointer BoxContent::addButton( + rpl::producer text, + Fn clickCallback, + const style::RoundButton &st) { + auto button = object_ptr(this, std::move(text), st); + auto result = QPointer(button.data()); + result->setTextTransform(RoundButton::TextTransform::NoTransform); + result->setClickedCallback(std::move(clickCallback)); + getDelegate()->addButton(std::move(button)); + return result; +} + +QPointer BoxContent::addLeftButton( + object_ptr button) { + auto result = QPointer(button.data()); + getDelegate()->addLeftButton(std::move(button)); + return result; +} + QPointer BoxContent::addLeftButton( rpl::producer text, Fn clickCallback) { - return getDelegate()->addLeftButton( + return addLeftButton( std::move(text), std::move(clickCallback), getDelegate()->style().button); } -void BoxContent::setInner(object_ptr inner) { - setInner(std::move(inner), st::boxScroll); +QPointer BoxContent::addLeftButton( + rpl::producer text, + Fn clickCallback, + const style::RoundButton &st) { + auto button = object_ptr(this, std::move(text), st); + const auto result = QPointer(button.data()); + result->setTextTransform(RoundButton::TextTransform::NoTransform); + result->setClickedCallback(std::move(clickCallback)); + getDelegate()->addLeftButton(std::move(button)); + return result; } -void BoxContent::setInner(object_ptr inner, const style::ScrollArea &st) { +QPointer BoxContent::addTopButton( + object_ptr button) { + auto result = QPointer(button.data()); + getDelegate()->addTopButton(std::move(button)); + return result; +} + +QPointer BoxContent::addTopButton( + const style::IconButton &st, + Fn clickCallback) { + auto button = object_ptr(this, st); + const auto result = QPointer(button.data()); + result->setClickedCallback(std::move(clickCallback)); + getDelegate()->addTopButton(std::move(button)); + return result; +} + +void BoxContent::setInner( + object_ptr inner, + const style::ScrollArea &st) { if (inner) { getDelegate()->setLayerType(true); _scroll.create(this, st); @@ -90,11 +236,19 @@ void BoxContent::finishScrollCreate() { updateScrollAreaGeometry(); _scroll->scrolls( ) | rpl::start_with_next([=] { - onScroll(); + updateInnerVisibleTopBottom(); + updateShadowsVisibility(); }, lifetime()); _scroll->innerResizes( ) | rpl::start_with_next([=] { - onInnerResize(); + updateInnerVisibleTopBottom(); + updateShadowsVisibility(); + }, lifetime()); + _draggingScroll.scrolls( + ) | rpl::start_with_next([=](int delta) { + if (_scroll) { + _scroll->scrollToY(_scroll->scrollTop() + delta); + } }, lifetime()); } @@ -108,60 +262,81 @@ RectParts BoxContent::customCornersFilling() { return {}; } -void BoxContent::onScrollToY(int top, int bottom) { +void BoxContent::scrollToY(int top, int bottom) { if (_scroll) { _scroll->scrollToY(top, bottom); } } -void BoxContent::scrollByDraggingDelta(int delta) { - _draggingScrollDelta = _scroll ? delta : 0; - if (_draggingScrollDelta) { - if (!_draggingScrollTimer) { - _draggingScrollTimer.create(this); - _draggingScrollTimer->setSingleShot(false); - connect(_draggingScrollTimer, SIGNAL(timeout()), this, SLOT(onDraggingScrollTimer())); - } - _draggingScrollTimer->start(15); - } else { - _draggingScrollTimer.destroy(); +void BoxContent::sendScrollViewportEvent(not_null event) { + if (_scroll) { + _scroll->viewportEvent(event); } } -void BoxContent::onDraggingScrollTimer() { - auto delta = (_draggingScrollDelta > 0) ? qMin(_draggingScrollDelta * 3 / 20 + 1, int32(kMaxScrollSpeed)) : qMax(_draggingScrollDelta * 3 / 20 - 1, -int32(kMaxScrollSpeed)); - _scroll->scrollToY(_scroll->scrollTop() + delta); +rpl::producer<> BoxContent::scrolls() const { + return _scroll ? _scroll->scrolls() : rpl::never<>(); +} + +int BoxContent::scrollTop() const { + return _scroll ? _scroll->scrollTop() : 0; +} + +int BoxContent::scrollHeight() const { + return _scroll ? _scroll->height() : 0; +} + +base::weak_ptr BoxContent::showToast( + Toast::Config &&config) { + return BoxShow(this).showToast(std::move(config)); +} + +base::weak_ptr BoxContent::showToast( + TextWithEntities &&text, + crl::time duration) { + return BoxShow(this).showToast(std::move(text), duration); +} + +base::weak_ptr BoxContent::showToast( + const QString &text, + crl::time duration) { + return BoxShow(this).showToast(text, duration); +} + +std::shared_ptr BoxContent::uiShow() { + return std::make_shared(this); +} + +void BoxContent::scrollByDraggingDelta(int delta) { + _draggingScroll.checkDeltaScroll(_scroll ? delta : 0); } void BoxContent::updateInnerVisibleTopBottom() { - if (auto widget = static_cast(_scroll ? _scroll->widget() : nullptr)) { - auto top = _scroll->scrollTop(); + const auto widget = static_cast(_scroll + ? _scroll->widget() + : nullptr); + if (widget) { + const auto top = _scroll->scrollTop(); widget->setVisibleTopBottom(top, top + _scroll->height()); } } -void BoxContent::updateShadowsVisibility() { - if (!_scroll) return; +void BoxContent::updateShadowsVisibility(anim::type animated) { + if (!_scroll) { + return; + } - auto top = _scroll->scrollTop(); + const auto top = _scroll->scrollTop(); _topShadow->toggle( - (top > 0 - || (_innerTopSkip > 0 && !_topShadowWithSkip)), - anim::type::normal); + ((top > 0) + || (_innerTopSkip > 0 + && !_topShadowWithSkip + && !getDelegate()->style().shadowIgnoreTopSkip)), + animated); _bottomShadow->toggle( (top < _scroll->scrollTopMax() || (_innerBottomSkip > 0 && !_bottomShadowWithSkip)), - anim::type::normal); -} - -void BoxContent::onScroll() { - updateInnerVisibleTopBottom(); - updateShadowsVisibility(); -} - -void BoxContent::onInnerResize() { - updateInnerVisibleTopBottom(); - updateShadowsVisibility(); + animated); } void BoxContent::setDimensionsToContent( @@ -176,7 +351,7 @@ void BoxContent::setDimensionsToContent( void BoxContent::setInnerTopSkip(int innerTopSkip, bool scrollBottomFixed) { if (_innerTopSkip != innerTopSkip) { - auto delta = innerTopSkip - _innerTopSkip; + const auto delta = innerTopSkip - _innerTopSkip; _innerTopSkip = innerTopSkip; if (_scroll && width() > 0) { auto scrollTopWas = _scroll->scrollTop(); @@ -204,13 +379,21 @@ void BoxContent::setInnerVisible(bool scrollAreaVisible) { } QPixmap BoxContent::grabInnerCache() { - auto isTopShadowVisible = !_topShadow->isHidden(); - auto isBottomShadowVisible = !_bottomShadow->isHidden(); - if (isTopShadowVisible) _topShadow->setVisible(false); - if (isBottomShadowVisible) _bottomShadow->setVisible(false); - auto result = GrabWidget(this, _scroll->geometry()); - if (isTopShadowVisible) _topShadow->setVisible(true); - if (isBottomShadowVisible) _bottomShadow->setVisible(true); + const auto isTopShadowVisible = !_topShadow->isHidden(); + const auto isBottomShadowVisible = !_bottomShadow->isHidden(); + if (isTopShadowVisible) { + _topShadow->setVisible(false); + } + if (isBottomShadowVisible) { + _bottomShadow->setVisible(false); + } + const auto result = GrabWidget(this, _scroll->geometry()); + if (isTopShadowVisible) { + _topShadow->setVisible(true); + } + if (isBottomShadowVisible) { + _bottomShadow->setVisible(true); + } return result; } @@ -229,8 +412,8 @@ void BoxContent::keyPressEvent(QKeyEvent *e) { } void BoxContent::updateScrollAreaGeometry() { - auto newScrollHeight = height() - _innerTopSkip - _innerBottomSkip; - auto changed = (_scroll->height() != newScrollHeight); + const auto newScrollHeight = height() - _innerTopSkip - _innerBottomSkip; + const auto changed = (_scroll->height() != newScrollHeight); _scroll->setGeometryToLeft(0, _innerTopSkip, width(), newScrollHeight); _topShadow->entity()->resize(width(), st::lineWidth); _topShadow->moveToLeft(0, _innerTopSkip); @@ -240,16 +423,7 @@ void BoxContent::updateScrollAreaGeometry() { height() - _innerBottomSkip - st::lineWidth); if (changed) { updateInnerVisibleTopBottom(); - - auto top = _scroll->scrollTop(); - _topShadow->toggle( - (top > 0 - || (_innerTopSkip > 0 && !_topShadowWithSkip)), - anim::type::instant); - _bottomShadow->toggle( - (top < _scroll->scrollTopMax() - || (_innerBottomSkip > 0 && !_bottomShadowWithSkip)), - anim::type::instant); + updateShadowsVisibility(anim::type::instant); } } diff --git a/ui/layers/box_content.h b/ui/layers/box_content.h index d2c6938..5526b41 100644 --- a/ui/layers/box_content.h +++ b/ui/layers/box_content.h @@ -8,9 +8,11 @@ #include "base/unique_qptr.h" #include "base/flags.h" +#include "ui/dragging_scroll_manager.h" #include "ui/wrap/padding_wrap.h" #include "ui/widgets/labels.h" #include "ui/layers/layer_widget.h" +#include "ui/layers/show.h" #include "ui/effects/animation_value.h" #include "ui/text/text_entity.h" #include "ui/rp_widget.h" @@ -18,6 +20,10 @@ enum class RectPart; using RectParts = base::flags; +namespace base { +class Timer; +} // namespace base + namespace style { struct RoundButton; struct IconButton; @@ -25,6 +31,15 @@ struct ScrollArea; struct Box; } // namespace style +namespace st { +extern const style::ScrollArea &boxScroll; +} // namespace st + +namespace Ui::Toast { +struct Config; +class Instance; +} // namespace Ui::Toast + namespace Ui { class GenericBox; } // namespace Ui @@ -37,6 +52,7 @@ inline object_ptr Box(Args &&...args) { namespace Ui { +class AbstractButton; class RoundButton; class IconButton; class ScrollArea; @@ -54,17 +70,9 @@ public: virtual void setCloseByOutsideClick(bool close) = 0; virtual void clearButtons() = 0; - virtual QPointer addButton( - rpl::producer text, - Fn clickCallback, - const style::RoundButton &st) = 0; - virtual QPointer addLeftButton( - rpl::producer text, - Fn clickCallback, - const style::RoundButton &st) = 0; - virtual QPointer addTopButton( - const style::IconButton &st, - Fn clickCallback) = 0; + virtual void addButton(object_ptr button) = 0; + virtual void addLeftButton(object_ptr button) = 0; + virtual void addTopButton(object_ptr button) = 0; virtual void showLoading(bool show) = 0; virtual void updateButtonsPositions() = 0; @@ -79,6 +87,7 @@ public: virtual void setNoContentMargin(bool noContentMargin) = 0; virtual bool isBoxShown() const = 0; virtual void closeBox() = 0; + virtual void hideLayer() = 0; virtual void triggerButton(int index) = 0; template @@ -91,13 +100,12 @@ public: return result; } + virtual ShowFactory showFactory() = 0; virtual QPointer outerContainer() = 0; }; class BoxContent : public RpWidget { - Q_OBJECT - public: BoxContent() { setAttribute(Qt::WA_OpaquePaintEvent); @@ -135,40 +143,31 @@ public: void clearButtons() { getDelegate()->clearButtons(); } + QPointer addButton(object_ptr button); QPointer addButton( rpl::producer text, Fn clickCallback = nullptr); + QPointer addButton( + rpl::producer text, + const style::RoundButton &st); + QPointer addButton( + rpl::producer text, + Fn clickCallback, + const style::RoundButton &st); + QPointer addLeftButton( + object_ptr button); + QPointer addLeftButton( + rpl::producer text, + Fn clickCallback = nullptr); QPointer addLeftButton( rpl::producer text, - Fn clickCallback = nullptr); + Fn clickCallback, + const style::RoundButton& st); + QPointer addTopButton( + object_ptr button); QPointer addTopButton( - const style::IconButton &st, - Fn clickCallback = nullptr) { - return getDelegate()->addTopButton(st, std::move(clickCallback)); - } - QPointer addButton( - rpl::producer text, - const style::RoundButton &st) { - return getDelegate()->addButton(std::move(text), nullptr, st); - } - QPointer addButton( - rpl::producer text, - Fn clickCallback, - const style::RoundButton &st) { - return getDelegate()->addButton( - std::move(text), - std::move(clickCallback), - st); - } - QPointer addLeftButton( - rpl::producer text, - Fn clickCallback, - const style::RoundButton& st) { - return getDelegate()->addLeftButton( - std::move(text), - std::move(clickCallback), - st); - } + const style::IconButton &st, + Fn clickCallback = nullptr); void showLoading(bool show) { getDelegate()->showLoading(show); } @@ -196,6 +195,9 @@ public: prepare(); finishPrepare(); } + [[nodiscard]] bool hasDelegate() const { + return _delegate != nullptr; + } [[nodiscard]] not_null getDelegate() const { return _delegate; } @@ -210,8 +212,21 @@ public: void scrollByDraggingDelta(int delta); -public Q_SLOTS: - void onScrollToY(int top, int bottom = -1); + void scrollToY(int top, int bottom = -1); + void sendScrollViewportEvent(not_null event); + [[nodiscard]] rpl::producer<> scrolls() const; + [[nodiscard]] int scrollTop() const; + [[nodiscard]] int scrollHeight() const; + + base::weak_ptr showToast(Toast::Config &&config); + base::weak_ptr showToast( + TextWithEntities &&text, + crl::time duration = 0); + base::weak_ptr showToast( + const QString &text, + crl::time duration = 0); + + [[nodiscard]] std::shared_ptr uiShow(); protected: virtual void prepare() = 0; @@ -260,11 +275,11 @@ protected: object_ptr inner, int topSkip = 0, int bottomSkip = 0) { - auto result = QPointer(inner.data()); - setInnerTopSkip(topSkip); - setInnerBottomSkip(bottomSkip); - setInner(std::move(inner)); - return result; + return setInnerWidget( + std::move(inner), + st::boxScroll, + topSkip, + bottomSkip); } template @@ -280,20 +295,13 @@ protected: void paintEvent(QPaintEvent *e) override; void keyPressEvent(QKeyEvent *e) override; -private Q_SLOTS: - void onScroll(); - void onInnerResize(); - - void onDraggingScrollTimer(); - private: void finishPrepare(); void finishScrollCreate(); - void setInner(object_ptr inner); void setInner(object_ptr inner, const style::ScrollArea &st); void updateScrollAreaGeometry(); void updateInnerVisibleTopBottom(); - void updateShadowsVisibility(); + void updateShadowsVisibility(anim::type animated = anim::type::normal); object_ptr doTakeInnerWidget(); BoxContentDelegate *_delegate = nullptr; @@ -309,8 +317,7 @@ private: object_ptr _topShadow = { nullptr }; object_ptr _bottomShadow = { nullptr }; - object_ptr _draggingScrollTimer = { nullptr }; - int _draggingScrollDelta = 0; + Ui::DraggingScrollManager _draggingScroll; rpl::event_stream<> _boxClosingStream; diff --git a/ui/layers/box_layer_widget.cpp b/ui/layers/box_layer_widget.cpp index cd2b494..6f356f9 100644 --- a/ui/layers/box_layer_widget.cpp +++ b/ui/layers/box_layer_widget.cpp @@ -8,12 +8,7 @@ #include "ui/effects/radial_animation.h" #include "ui/widgets/buttons.h" -#include "ui/widgets/scroll_area.h" #include "ui/widgets/labels.h" -#include "ui/widgets/shadow.h" -#include "ui/wrap/fade_wrap.h" -#include "ui/text/text_utilities.h" -#include "ui/image/image_prepare.h" #include "ui/painter.h" #include "base/timer.h" #include "styles/style_layers.h" @@ -42,7 +37,7 @@ BoxLayerWidget::BoxLayerWidget( : LayerWidget(layer) , _layer(layer) , _content(std::move(content)) -, _roundRect(ImageRoundRadius::Small, st().bg) { +, _roundRect(st::boxRadius, st().bg) { _content->setParent(this); _content->setDelegate(this); @@ -217,6 +212,10 @@ void BoxLayerWidget::showBox( _layer->showBox(std::move(box), options, animated); } +void BoxLayerWidget::hideLayer() { + _layer->hideLayers(anim::type::normal); +} + void BoxLayerWidget::updateSize() { setDimensions(width(), _maxContentHeight); } @@ -239,6 +238,10 @@ void BoxLayerWidget::updateButtonsPositions() { } } +ShowFactory BoxLayerWidget::showFactory() { + return _layer->showFactory(); +} + QPointer BoxLayerWidget::outerContainer() { return parentWidget(); } @@ -247,11 +250,11 @@ void BoxLayerWidget::updateTitlePosition() { _titleLeft = st::boxTitlePosition.x(); _titleTop = st::boxTitlePosition.y(); if (_title) { - const auto topButtonSkip = _topButton ? (_topButton->width() / 2) : 0; - _title->resizeToWidth( - std::min( - _title->naturalWidth(), - width() - _titleLeft * 2 - topButtonSkip)); + const auto topButtonSkip = _topButton + ? (_topButton->width() / 2) + : 0; + _title->resizeToNaturalWidth( + width() - _titleLeft * 2 - topButtonSkip); _title->moveToLeft(_titleLeft, _titleTop); } } @@ -264,44 +267,35 @@ void BoxLayerWidget::clearButtons() { _topButton = nullptr; } -QPointer BoxLayerWidget::addButton( - rpl::producer text, - Fn clickCallback, - const style::RoundButton &st) { - _buttons.emplace_back(this, std::move(text), st); - auto result = QPointer(_buttons.back()); - result->setClickedCallback(std::move(clickCallback)); - result->show(); - result->widthValue( +void BoxLayerWidget::addButton(object_ptr button) { + _buttons.push_back(std::move(button)); + const auto raw = _buttons.back().data(); + raw->setParent(this); + raw->show(); + raw->widthValue( ) | rpl::start_with_next([=] { updateButtonsPositions(); - }, result->lifetime()); - return result; + }, raw->lifetime()); } -QPointer BoxLayerWidget::addLeftButton( - rpl::producer text, - Fn clickCallback, - const style::RoundButton &st) { - _leftButton = object_ptr(this, std::move(text), st); - auto result = QPointer(_leftButton); - result->setClickedCallback(std::move(clickCallback)); - result->show(); - result->widthValue( +void BoxLayerWidget::addLeftButton(object_ptr button) { + _leftButton = std::move(button); + const auto raw = _leftButton.data(); + raw->setParent(this); + raw->show(); + raw->widthValue( ) | rpl::start_with_next([=] { updateButtonsPositions(); - }, result->lifetime()); - return result; + }, raw->lifetime()); } -QPointer BoxLayerWidget::addTopButton(const style::IconButton &st, Fn clickCallback) { - _topButton = base::make_unique_q(this, st); - auto result = QPointer(_topButton.get()); - result->setClickedCallback(std::move(clickCallback)); - result->show(); +void BoxLayerWidget::addTopButton(object_ptr button) { + _topButton = base::unique_qptr(button.release()); + const auto raw = _topButton.get(); + raw->setParent(this); + raw->show(); updateButtonsPositions(); updateTitlePosition(); - return result; } void BoxLayerWidget::showLoading(bool show) { @@ -377,14 +371,19 @@ int BoxLayerWidget::countFullHeight() const { } int BoxLayerWidget::contentTop() const { - return hasTitle() ? titleHeight() : (_noContentMargin ? 0 : st::boxTopMargin); + return hasTitle() + ? titleHeight() + : _noContentMargin + ? + 0 + : st::boxTopMargin; } void BoxLayerWidget::resizeEvent(QResizeEvent *e) { updateButtonsPositions(); updateTitlePosition(); - auto top = contentTop(); + const auto top = contentTop(); _content->resize(width(), height() - top - buttonsHeight()); _content->moveToLeft(0, top); diff --git a/ui/layers/box_layer_widget.h b/ui/layers/box_layer_widget.h index a26c5ad..4200ab9 100644 --- a/ui/layers/box_layer_widget.h +++ b/ui/layers/box_layer_widget.h @@ -10,29 +10,24 @@ #include "base/flags.h" #include "ui/layers/layer_widget.h" #include "ui/layers/box_content.h" -#include "ui/wrap/padding_wrap.h" -#include "ui/widgets/labels.h" -#include "ui/effects/animation_value.h" -#include "ui/text/text_entity.h" #include "ui/round_rect.h" #include "ui/rp_widget.h" class Painter; +struct TextWithEntities; + +namespace anim { +enum class type : uchar; +} // namespace anim namespace style { -struct RoundButton; -struct IconButton; -struct ScrollArea; struct Box; } // namespace style namespace Ui { -class RoundButton; -class IconButton; -class ScrollArea; +class AbstractButton; class FlatLabel; -class FadeShadow; class BoxLayerWidget : public LayerWidget, public BoxContentDelegate { public: @@ -58,19 +53,12 @@ public: } void clearButtons() override; - QPointer addButton( - rpl::producer text, - Fn clickCallback, - const style::RoundButton &st) override; - QPointer addLeftButton( - rpl::producer text, - Fn clickCallback, - const style::RoundButton &st) override; - QPointer addTopButton( - const style::IconButton &st, - Fn clickCallback) override; + void addButton(object_ptr button) override; + void addLeftButton(object_ptr button) override; + void addTopButton(object_ptr button) override; void showLoading(bool show) override; void updateButtonsPositions() override; + ShowFactory showFactory() override; QPointer outerContainer() override; void setDimensions( @@ -91,6 +79,7 @@ public: void closeBox() override { closeLayer(); } + void hideLayer() override; void triggerButton(int index) override; void setCloseByOutsideClick(bool close) override; @@ -127,6 +116,7 @@ private: const style::Box *_st = nullptr; not_null _layer; + bool _layerType = false; int _fullHeight = 0; bool _noContentMargin = false; @@ -139,12 +129,11 @@ private: rpl::variable _additionalTitle; int _titleLeft = 0; int _titleTop = 0; - bool _layerType = false; bool _closeByOutsideClick = true; - std::vector> _buttons; - object_ptr _leftButton = { nullptr }; - base::unique_qptr _topButton = { nullptr }; + std::vector> _buttons; + object_ptr _leftButton = { nullptr }; + base::unique_qptr _topButton = { nullptr }; std::unique_ptr _loadingProgress; }; diff --git a/ui/layers/generic_box.cpp b/ui/layers/generic_box.cpp index 447bf8c..bfcc7aa 100644 --- a/ui/layers/generic_box.cpp +++ b/ui/layers/generic_box.cpp @@ -16,17 +16,116 @@ namespace Ui { void GenericBox::prepare() { _init(this); + const auto currentWidth = width(); + const auto pinnedToTop = _pinnedToTopContent.data(); + const auto pinnedToBottom = _pinnedToBottomContent.data(); + if (pinnedToTop) { + pinnedToTop->resizeToWidth(currentWidth); + } + if (pinnedToBottom) { + pinnedToBottom->resizeToWidth(currentWidth); + } + auto wrap = object_ptr(this, std::move(_owned)); - setDimensionsToContent(_width ? _width : st::boxWidth, wrap.data()); - setInnerWidget(std::move(wrap)); + wrap->resizeToWidth(currentWidth); + rpl::combine( + pinnedToTop ? pinnedToTop->heightValue() : rpl::single(0), + wrap->heightValue(), + pinnedToBottom ? pinnedToBottom->heightValue() : rpl::single(0) + ) | rpl::start_with_next([=](int top, int height, int bottom) { + Expects(_minHeight >= 0); + Expects(!_maxHeight || _minHeight <= _maxHeight); + + setInnerTopSkip(top); + setInnerBottomSkip(bottom); + const auto desired = top + height + bottom; + setDimensions( + currentWidth, + std::clamp( + desired, + _minHeight, + _maxHeight ? _maxHeight : std::max(_minHeight, desired)), + true); + }, wrap->lifetime()); + + setInnerWidget( + std::move(wrap), + _scrollSt ? *_scrollSt : st::boxScroll, + pinnedToTop ? pinnedToTop->height() : 0, + pinnedToBottom ? pinnedToBottom->height() : 0); + + if (pinnedToBottom) { + rpl::combine( + heightValue(), + pinnedToBottom->heightValue() + ) | rpl::start_with_next([=](int outer, int height) { + pinnedToBottom->move(0, outer - height); + }, pinnedToBottom->lifetime()); + } + + if (const auto onstack = _initScroll) { + onstack(); + } } void GenericBox::addSkip(int height) { addRow(object_ptr(this, height)); } +void GenericBox::setInnerFocus() { + if (_focus) { + _focus(); + } else { + BoxContent::setInnerFocus(); + } +} + +void GenericBox::showFinished() { + const auto guard = QPointer(this); + if (const auto onstack = _showFinished) { + onstack(); + if (!guard) { + return; + } + } + _showFinishes.fire({}); +} + +not_null GenericBox::doSetPinnedToTopContent( + object_ptr content) { + _pinnedToTopContent = std::move(content); + return _pinnedToTopContent.data(); +} + +not_null GenericBox::doSetPinnedToBottomContent( + object_ptr content) { + _pinnedToBottomContent = std::move(content); + return _pinnedToBottomContent.data(); +} + +int GenericBox::rowsCount() const { + return _content->count(); +} + +int GenericBox::width() const { + return _width ? _width : st::boxWidth; +} + not_null GenericBox::verticalLayout() { return _content; } +rpl::producer<> BoxShowFinishes(not_null box) { + const auto singleShot = box->lifetime().make_state(); + const auto showFinishes = singleShot->make_state>(); + + box->setShowFinishedCallback([=] { + showFinishes->fire({}); + singleShot->destroy(); + box->setShowFinishedCallback(nullptr); + }); + + return showFinishes->events(); +} + } // namespace Ui diff --git a/ui/layers/generic_box.h b/ui/layers/generic_box.h index b6832f8..53be668 100644 --- a/ui/layers/generic_box.h +++ b/ui/layers/generic_box.h @@ -38,14 +38,19 @@ public: void setFocusCallback(Fn callback) { _focus = callback; } + void setInitScrollCallback(Fn callback) { + _initScroll = callback; + } void setShowFinishedCallback(Fn callback) { _showFinished = callback; } - - int rowsCount() const { - return _content->count(); + [[nodiscard]] rpl::producer<> showFinishes() const { + return _showFinishes.events(); } + [[nodiscard]] int rowsCount() const; + [[nodiscard]] int width() const; + template < typename Widget, typename = std::enable_if_t< @@ -72,26 +77,35 @@ public: void addSkip(int height); - void setInnerFocus() override { - if (_focus) { - _focus(); - } else { - BoxContent::setInnerFocus(); - } + void setMaxHeight(int maxHeight) { + _maxHeight = maxHeight; } - void showFinished() override { - if (_showFinished) { - _showFinished(); - } + void setMinHeight(int minHeight) { + _minHeight = minHeight; + } + void setScrollStyle(const style::ScrollArea &st) { + _scrollSt = &st; + } + + void setInnerFocus() override; + void showFinished() override; + + template + not_null setPinnedToTopContent(object_ptr content) { + return static_cast( + doSetPinnedToTopContent(std::move(content)).get()); + } + + template + not_null setPinnedToBottomContent(object_ptr content) { + return static_cast( + doSetPinnedToBottomContent(std::move(content)).get()); } [[nodiscard]] not_null verticalLayout(); using BoxContent::setNoContentMargin; -protected: - void prepare() override; - private: template struct Initer { @@ -117,12 +131,26 @@ private: auto MakeIniter(InitMethod &&method, InitArgs &&...args) -> Initer, std::decay_t...>; + void prepare() override; + not_null doSetPinnedToTopContent( + object_ptr content); + not_null doSetPinnedToBottomContent( + object_ptr content); + FnMut)> _init; Fn _focus; + Fn _initScroll; Fn _showFinished; + rpl::event_stream<> _showFinishes; object_ptr _owned; not_null _content; + const style::ScrollArea *_scrollSt = nullptr; int _width = 0; + int _minHeight = 0; + int _maxHeight = 0; + + object_ptr _pinnedToTopContent = { nullptr }; + object_ptr _pinnedToBottomContent = { nullptr }; }; @@ -171,4 +199,6 @@ inline GenericBox::GenericBox( , _content(_owned.data()) { } +[[nodiscard]] rpl::producer<> BoxShowFinishes(not_null box); + } // namespace Ui diff --git a/ui/layers/layer_manager.cpp b/ui/layers/layer_manager.cpp index 91e3e9e..a6470ac 100644 --- a/ui/layers/layer_manager.cpp +++ b/ui/layers/layer_manager.cpp @@ -6,9 +6,76 @@ // #include "ui/layers/layer_manager.h" +#include "ui/layers/show.h" + namespace Ui { -LayerManager::LayerManager(not_null widget) : _widget(widget) { +class LayerManager::ManagerShow final : public Show { +public: + explicit ManagerShow(not_null manager); + ~ManagerShow(); + + void showOrHideBoxOrLayer( + std::variant< + v::null_t, + object_ptr, + std::unique_ptr> &&layer, + LayerOptions options, + anim::type animated) const override; + [[nodiscard]] not_null toastParent() const override; + [[nodiscard]] bool valid() const override; + operator bool() const override; + +private: + const base::weak_ptr _manager; + +}; + +LayerManager::ManagerShow::ManagerShow(not_null manager) +: _manager(manager.get()) { +} + +LayerManager::ManagerShow::~ManagerShow() = default; + +void LayerManager::ManagerShow::showOrHideBoxOrLayer( + std::variant< + v::null_t, + object_ptr, + std::unique_ptr> &&layer, + LayerOptions options, + anim::type animated) const { + using UniqueLayer = std::unique_ptr; + using ObjectBox = object_ptr; + if (auto layerWidget = std::get_if(&layer)) { + if (const auto manager = _manager.get()) { + manager->showLayer(std::move(*layerWidget), options, animated); + } + } else if (auto box = std::get_if(&layer)) { + if (const auto manager = _manager.get()) { + manager->showBox(std::move(*box), options, animated); + } + } else if (const auto manager = _manager.get()) { + manager->hideAll(animated); + } +} + +not_null LayerManager::ManagerShow::toastParent() const { + const auto manager = _manager.get(); + + Ensures(manager != nullptr); + return manager->toastParent(); +} + +bool LayerManager::ManagerShow::valid() const { + return (_manager.get() != nullptr); +} + +LayerManager::ManagerShow::operator bool() const { + return valid(); +} + +LayerManager::LayerManager(not_null widget) +: _widget(widget) { } void LayerManager::setStyleOverrides( @@ -37,6 +104,15 @@ void LayerManager::showBox( setFocus(); } +void LayerManager::showLayer( + std::unique_ptr layer, + LayerOptions options, + anim::type animated) { + ensureLayerCreated(); + _layer->showLayer(std::move(layer), options, animated); + setFocus(); +} + void LayerManager::hideAll(anim::type animated) { if (animated == anim::type::instant) { destroyLayer(); @@ -59,6 +135,13 @@ bool LayerManager::setFocus() { return true; } +std::shared_ptr LayerManager::uiShow() { + if (!_cachedShow) { + _cachedShow = std::make_shared(this); + } + return _cachedShow; +} + const LayerWidget *LayerManager::topShownLayer() const { return _layer ? _layer->topShownLayer() : nullptr; } @@ -67,7 +150,9 @@ void LayerManager::ensureLayerCreated() { if (_layer) { return; } - _layer.emplace(_widget); + _layer.emplace(_widget, crl::guard(this, [=] { + return uiShow(); + })); _layer->setHideByBackgroundClick(_hideByBackgroundClick); _layer->setStyleOverrides(_boxSt, _layerSt); @@ -83,6 +168,8 @@ void LayerManager::ensureLayerCreated() { ) | rpl::start_with_next([=](QSize size) { _layer->resize(size); }, _layer->lifetime()); + + _layerShown = true; } void LayerManager::destroyLayer() { @@ -91,6 +178,8 @@ void LayerManager::destroyLayer() { } auto layer = base::take(_layer); + _layerShown = false; + const auto resetFocus = Ui::InFocusChain(layer); if (resetFocus) { _widget->setFocus(); diff --git a/ui/layers/layer_manager.h b/ui/layers/layer_manager.h index cce68dc..b8ce72b 100644 --- a/ui/layers/layer_manager.h +++ b/ui/layers/layer_manager.h @@ -6,6 +6,7 @@ // #pragma once +#include "base/weak_ptr.h" #include "ui/layers/layer_widget.h" #include @@ -18,8 +19,9 @@ namespace Ui { class BoxContent; class RpWidget; +class Show; -class LayerManager final { +class LayerManager final : public base::has_weak_ptr { public: explicit LayerManager(not_null widget); @@ -32,18 +34,35 @@ public: object_ptr box, LayerOptions options = LayerOption::KeepOther, anim::type animated = anim::type::normal); + void showLayer( + std::unique_ptr layer, + LayerOptions options = LayerOption::KeepOther, + anim::type animated = anim::type::normal); void hideAll(anim::type animated = anim::type::normal); void raise(); bool setFocus(); - const LayerWidget *topShownLayer() const; + [[nodiscard]] rpl::producer layerShownValue() const { + return _layerShown.value(); + } + + [[nodiscard]] not_null toastParent() const { + return _widget; + } + [[nodiscard]] const LayerWidget *topShownLayer() const; + + [[nodiscard]] std::shared_ptr uiShow(); private: + class ManagerShow; + void ensureLayerCreated(); void destroyLayer(); const not_null _widget; base::unique_qptr _layer; + std::shared_ptr _cachedShow; + rpl::variable _layerShown; const style::Box *_boxSt = nullptr; const style::Box *_layerSt = nullptr; diff --git a/ui/layers/layer_widget.cpp b/ui/layers/layer_widget.cpp index 7d8722c..b91c2f5 100644 --- a/ui/layers/layer_widget.cpp +++ b/ui/layers/layer_widget.cpp @@ -6,11 +6,15 @@ // #include "ui/layers/layer_widget.h" +#include "ui/cached_special_layer_shadow_corners.h" #include "ui/layers/box_layer_widget.h" #include "ui/widgets/shadow.h" #include "ui/image/image_prepare.h" +#include "ui/painter.h" #include "ui/ui_utility.h" #include "ui/round_rect.h" +#include "base/qt/qt_tab_key.h" +#include "base/integration.h" #include "styles/style_layers.h" #include "styles/style_widgets.h" #include "styles/palette.h" @@ -21,7 +25,7 @@ namespace Ui { class LayerStackWidget::BackgroundWidget : public TWidget { public: - explicit BackgroundWidget(QWidget *parent); + using TWidget::TWidget; void setDoneCallback(Fn callback) { _doneCallback = std::move(callback); @@ -63,12 +67,12 @@ private: int _mainMenuCacheWidth = 0; QPixmap _specialLayerCache; QPixmap _layerCache; - RoundRect _roundRect; Fn _doneCallback; bool _wasAnimating = false; bool _inPaintEvent = false; + bool _repaintIssued = false; Ui::Animations::Simple _a_shown; Ui::Animations::Simple _a_mainMenuShown; Ui::Animations::Simple _a_specialLayerShown; @@ -84,11 +88,6 @@ private: }; -LayerStackWidget::BackgroundWidget::BackgroundWidget(QWidget *parent) -: TWidget(parent) -, _roundRect(ImageRoundRadius::Small, st::boxBg) { -} - void LayerStackWidget::BackgroundWidget::setCacheImages( QPixmap &&bodyCache, QPixmap &&mainMenuCache, @@ -100,6 +99,7 @@ void LayerStackWidget::BackgroundWidget::setCacheImages( _layerCache = std::move(layerCache); _specialLayerCacheBox = _specialLayerBox; _layerCacheBox = _layerBox; + _repaintIssued = false; setAttribute(Qt::WA_OpaquePaintEvent, !_bodyCache.isNull()); } @@ -145,6 +145,7 @@ void LayerStackWidget::BackgroundWidget::startAnimation(Action action) { } void LayerStackWidget::BackgroundWidget::skipAnimation(Action action) { + _repaintIssued = false; startAnimation(action); finishAnimating(); } @@ -262,15 +263,9 @@ void LayerStackWidget::BackgroundWidget::paintEvent(QPaintEvent *e) { if (topCorners || bottomCorners) { p.setClipRegion(QRegion(rect()) - specialLayerBox.marginsRemoved(QMargins(st::boxRadius, 0, st::boxRadius, 0)) - specialLayerBox.marginsRemoved(QMargins(0, st::boxRadius, 0, st::boxRadius))); } - Ui::Shadow::paint(p, specialLayerBox, width(), st::boxRoundShadow, sides); - + Ui::Shadow::paint(p, specialLayerBox, width(), st::boxRoundShadow, Ui::SpecialLayerShadowCorners(), sides); if (topCorners || bottomCorners) { - // In case of painting the shadow above the special layer we get - // glitches in the corners, so we need to paint the corners once more. p.setClipping(false); - auto parts = (topCorners ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None) - | (bottomCorners ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None); - _roundRect.paint(p, specialLayerBox, parts); } } @@ -318,6 +313,10 @@ void LayerStackWidget::BackgroundWidget::paintEvent(QPaintEvent *e) { auto sourceRect = style::rtlrect(_mainMenuCache.width() - sourceWidth, 0, sourceWidth, _mainMenuCache.height(), _mainMenuCache.width()); p.drawPixmapLeft(0, 0, shownWidth, height(), width(), _mainMenuCache, sourceRect); } + if (!_repaintIssued && !_a_shown.animating()) { + _repaintIssued = true; + update(); + } } void LayerStackWidget::BackgroundWidget::finishAnimating() { @@ -333,9 +332,10 @@ void LayerStackWidget::BackgroundWidget::animationCallback() { checkIfDone(); } -LayerStackWidget::LayerStackWidget(QWidget *parent) +LayerStackWidget::LayerStackWidget(QWidget *parent, ShowFactory showFactory) : RpWidget(parent) -, _background(this) { +, _background(this) +, _showFactory(std::move(showFactory)) { setGeometry(parentWidget()->rect()); hide(); _background->setDoneCallback([this] { animationDone(); }); @@ -374,6 +374,10 @@ void LayerWidget::resizeEvent(QResizeEvent *e) { } } +bool LayerWidget::focusNextPrevChild(bool next) { + return base::FocusNextPrevChildBlocked(this, next); +} + void LayerStackWidget::setHideByBackgroundClick(bool hide) { _hideByBackgroundClick = hide; } @@ -688,16 +692,20 @@ void LayerStackWidget::prepareForAnimation() { } void LayerStackWidget::animationDone() { + auto &integration = base::Integration::Instance(); bool hidden = true; if (_mainMenu) { + integration.setCrashAnnotation("ShowingWidget", u"MainMenu"_q); _mainMenu->show(); hidden = false; } if (_specialLayer) { + integration.setCrashAnnotation("ShowingWidget", u"SpecialLayer"_q); _specialLayer->show(); hidden = false; } if (auto layer = currentLayer()) { + integration.setCrashAnnotation("ShowingWidget", u"Box"_q); layer->show(); hidden = false; } @@ -705,7 +713,9 @@ void LayerStackWidget::animationDone() { if (hidden) { _hideFinishStream.fire({}); } else { + integration.setCrashAnnotation("ShowingWidget", u"Finished"_q); showFinished(); + integration.setCrashAnnotation("ShowingWidget", QString()); } } @@ -720,6 +730,9 @@ void LayerStackWidget::showFinished() { if (_specialLayer) { _specialLayer->showFinished(); } + if (_mainMenu) { + _mainMenu->showFinished(); + } if (auto layer = currentLayer()) { layer->showFinished(); } diff --git a/ui/layers/layer_widget.h b/ui/layers/layer_widget.h index 7d7e337..096e551 100644 --- a/ui/layers/layer_widget.h +++ b/ui/layers/layer_widget.h @@ -32,7 +32,11 @@ enum class LayerOption { using LayerOptions = base::flags; inline constexpr auto is_flag_type(LayerOption) { return true; }; -class LayerWidget : public Ui::RpWidget { +class Show; +using ShowPtr = std::shared_ptr; +using ShowFactory = Fn; + +class LayerWidget : public RpWidget { public: using RpWidget::RpWidget; @@ -69,14 +73,17 @@ public: return true; } -protected: void closeLayer() { if (const auto callback = base::take(_closedCallback)) { callback(); } } + +protected: void mousePressEvent(QMouseEvent *e) override; void resizeEvent(QResizeEvent *e) override; + bool focusNextPrevChild(bool next) override; + virtual void doSetInnerFocus() { setFocus(); } @@ -90,9 +97,9 @@ private: }; -class LayerStackWidget : public Ui::RpWidget { +class LayerStackWidget : public RpWidget { public: - LayerStackWidget(QWidget *parent); + LayerStackWidget(QWidget *parent, ShowFactory showFactory); void finishAnimating(); rpl::producer<> hideFinishEvents() const; @@ -106,6 +113,9 @@ public: [[nodiscard]] const style::Box *boxStyleOverride() const { return _boxSt; } + [[nodiscard]] ShowFactory showFactory() const { + return _showFactory; + } void showBox( object_ptr box, @@ -221,6 +231,8 @@ private: class BackgroundWidget; object_ptr _background; + ShowFactory _showFactory; + const style::Box *_boxSt = nullptr; const style::Box *_layerSt = nullptr; bool _hideByBackgroundClick = true; diff --git a/ui/layers/layers.style b/ui/layers/layers.style index fcdb708..567b3f3 100644 --- a/ui/layers/layers.style +++ b/ui/layers/layers.style @@ -29,16 +29,18 @@ Box { title: FlatLabel; bg: color; titleAdditionalFg: color; + shadowIgnoreTopSkip: bool; } boxDuration: 200; -boxRadius: 3px; +boxRadius: 8px; boxButtonFont: font(boxFontSize semibold); defaultBoxButton: RoundButton(defaultLightButton) { - width: -24px; - height: 36px; - font: boxButtonFont; + width: -30px; + height: 34px; + textTop: 7px; + font: font(14px semibold); } boxLabelStyle: TextStyle(boxTextStyle) { @@ -74,26 +76,26 @@ boxRoundShadow: Shadow { fallback: windowShadowFgFallback; } -boxTitleFont: font(17px semibold); +boxTitleFont: font(16px semibold); boxTitle: FlatLabel(defaultFlatLabel) { textFg: boxTitleFg; maxHeight: 24px; style: TextStyle(defaultTextStyle) { font: boxTitleFont; - linkFont: boxTitleFont; - linkFontOver: font(17px semibold underline); } } -boxTitlePosition: point(22px, 16px); -boxTitleHeight: 56px; +boxTitlePosition: point(24px, 13px); +boxTitleHeight: 48px; boxTitleAdditionalSkip: 9px; boxTitleAdditionalFont: normalFont; boxScroll: defaultSolidScroll; -boxRowPadding: margins(22px, 0px, 22px, 0px); +boxRowPadding: margins(24px, 0px, 24px, 0px); -boxTopMargin: 6px; +boxTopMargin: 8px; +boxTitleCloseIcon: icon {{ "box_button_close", boxTitleCloseFg }}; +boxTitleCloseIconOver: icon {{ "box_button_close", boxTitleCloseFgOver }}; boxTitleClose: IconButton(defaultIconButton) { width: boxTitleHeight; height: boxTitleHeight; @@ -101,8 +103,8 @@ boxTitleClose: IconButton(defaultIconButton) { icon: boxTitleCloseIcon; iconOver: boxTitleCloseIconOver; - rippleAreaPosition: point(6px, 6px); - rippleAreaSize: 44px; + rippleAreaPosition: point(4px, 4px); + rippleAreaSize: 40px; ripple: RippleAnimation(defaultRippleAnimation) { color: windowBgOver; } @@ -115,18 +117,17 @@ boxLinkButton: LinkButton(defaultLinkButton) { boxOptionListPadding: margins(0px, 0px, 0px, 0px); boxOptionListSkip: 20px; -boxOptionInputSkip: 6px; boxWidth: 320px; boxWideWidth: 364px; -boxPadding: margins(22px, 30px, 22px, 8px); +boxPadding: margins(24px, 14px, 24px, 8px); boxMaxListHeight: 492px; boxLittleSkip: 10px; boxMediumSkip: 20px; defaultBox: Box { - buttonPadding: margins(8px, 12px, 13px, 12px); - buttonHeight: 36px; + buttonPadding: margins(6px, 10px, 10px, 10px); + buttonHeight: 34px; button: defaultBoxButton; margin: margins(0px, 10px, 0px, 10px); bg: boxBg; @@ -134,10 +135,10 @@ defaultBox: Box { titleAdditionalFg: boxTitleAdditionalFg; } layerBox: Box(defaultBox) { - buttonPadding: margins(8px, 8px, 8px, 8px); } boxLabel: FlatLabel(defaultFlatLabel) { - minWidth: 274px; + // Keep minWidth <= boxWidth - boxPadding.left - boxPadding.right. + minWidth: 256px; align: align(topleft); style: boxLabelStyle; } @@ -147,6 +148,7 @@ boxDividerLabel: FlatLabel(boxLabel) { textFg: windowSubTextFg; style: defaultTextStyle; } +defaultBoxDividerLabelPadding: margins(22px, 8px, 22px, 16px); boxLoadingAnimation: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) { color: windowSubTextFg; @@ -156,4 +158,62 @@ boxLoadingSize: 20px; boxDividerTop: icon {{ "box_divider_top", boxDividerFg }}; boxDividerBottom: icon {{ "box_divider_bottom", boxDividerFg }}; -boxDividerHeight: 10px; +boxDividerHeight: 8px; + +defaultSubsectionTitle: FlatLabel(defaultFlatLabel) { + style: TextStyle(semiboldTextStyle) { + font: font(boxFontSize semibold); + } + textFg: windowActiveTextFg; + minWidth: 240px; +} +defaultSubsectionTitlePadding: margins(22px, 7px, 10px, 9px); + +separatePanelBorderCacheSize: 60px; +separatePanelTitleHeight: 62px; +separatePanelNoTitleHeight: 32px; +separatePanelClose: IconButton(boxTitleClose) { + width: 60px; + height: 60px; + + rippleAreaPosition: point(8px, 8px); + rippleAreaSize: 44px; + ripple: RippleAnimation(defaultRippleAnimation) { + color: windowBgOver; + } +} +separatePanelMenu: IconButton(separatePanelClose) { + width: 44px; + + icon: icon {{ "title_menu_dots", boxTitleCloseFg }}; + iconOver: icon {{ "title_menu_dots", boxTitleCloseFgOver }}; + + rippleAreaPosition: point(0px, 8px); +} +separatePanelMenuPosition: point(0px, 52px); +separatePanelTitleFont: font(18px semibold); +separatePanelTitle: FlatLabel(defaultFlatLabel) { + textFg: boxTitleFg; + maxHeight: 26px; + style: TextStyle(defaultTextStyle) { + font: separatePanelTitleFont; + } +} +separatePanelTitleTop: 18px; +separatePanelTitleLeft: 22px; +separatePanelTitleSkip: 0px; +separatePanelBack: IconButton(separatePanelClose) { + icon: icon {{ "box_button_back", boxTitleCloseFg }}; + iconOver: icon {{ "box_button_back", boxTitleCloseFgOver }}; +} +separatePanelDuration: 150; + +webviewDialogButton: defaultBoxButton; +webviewDialogDestructiveButton: attentionBoxButton; +webviewDialogSubmit: RoundButton(defaultActiveButton) { + width: -48px; + height: 34px; + textTop: 7px; + font: font(14px semibold); +} +webviewDialogPadding: margins(8px, 12px, 15px, 12px); diff --git a/ui/layers/show.cpp b/ui/layers/show.cpp new file mode 100644 index 0000000..f28c64b --- /dev/null +++ b/ui/layers/show.cpp @@ -0,0 +1,61 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/layers/show.h" + +#include "ui/toast/toast.h" + +namespace Ui { +namespace { + +using namespace Toast; + +} // namespace + +void Show::showBox( + object_ptr content, + LayerOptions options, + anim::type animated) const { + return showOrHideBoxOrLayer(std::move(content), options, animated); +} + +void Show::showLayer( + std::unique_ptr layer, + LayerOptions options, + anim::type animated) const { + return showOrHideBoxOrLayer(std::move(layer), options, animated); +} + +void Show::hideLayer(anim::type animated) const { + return showOrHideBoxOrLayer(v::null, LayerOptions(), animated); +} + +base::weak_ptr Show::showToast(Config &&config) const { + if (const auto strong = _lastToast.get()) { + strong->hideAnimated(); + } + _lastToast = valid() + ? Toast::Show(toastParent(), std::move(config)) + : base::weak_ptr(); + return _lastToast; +} + +base::weak_ptr Show::showToast( + TextWithEntities &&text, + crl::time duration) const { + return showToast({ .text = std::move(text), .duration = duration }); +} + +base::weak_ptr Show::showToast( + const QString &text, + crl::time duration) const { + return showToast({ + .text = TextWithEntities{ text }, + .duration = duration, + }); +} + +} // namespace Ui diff --git a/ui/layers/show.h b/ui/layers/show.h new file mode 100644 index 0000000..37413fd --- /dev/null +++ b/ui/layers/show.h @@ -0,0 +1,81 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +#include "base/weak_ptr.h" +#include "ui/layers/layer_widget.h" + +struct TextWithEntities; + +namespace anim { +enum class type : uchar; +} // namespace anim + +namespace Ui::Toast { +struct Config; +class Instance; +} // namespace Ui::Toast + +namespace Ui { + +class BoxContent; +class LayerWidget; + +inline constexpr auto kZOrderBasic = 0; + +class Show { +public: + virtual ~Show() = 0; + virtual void showOrHideBoxOrLayer( + std::variant< + v::null_t, + object_ptr, + std::unique_ptr> &&layer, + LayerOptions options, + anim::type animated) const = 0; + [[nodiscard]] virtual not_null toastParent() const = 0; + [[nodiscard]] virtual bool valid() const = 0; + virtual operator bool() const = 0; + + void showBox( + object_ptr content, + LayerOptions options = LayerOption::KeepOther, + anim::type animated = anim::type()) const; + void showLayer( + std::unique_ptr layer, + LayerOptions options = LayerOption::KeepOther, + anim::type animated = anim::type()) const; + void hideLayer(anim::type animated = anim::type()) const; + + base::weak_ptr showToast(Toast::Config &&config) const; + base::weak_ptr showToast( + TextWithEntities &&text, + crl::time duration = 0) const; + base::weak_ptr showToast( + const QString &text, + crl::time duration = 0) const; + + template < + typename BoxType, + typename = std::enable_if_t>> + QPointer show( + object_ptr content, + LayerOptions options = LayerOption::KeepOther, + anim::type animated = anim::type()) const { + auto result = QPointer(content.data()); + showBox(std::move(content), options, animated); + return result; + } + +private: + mutable base::weak_ptr _lastToast; + +}; + +inline Show::~Show() = default; + +} // namespace Ui diff --git a/ui/main_queue_processor.cpp b/ui/main_queue_processor.cpp index 3915fb5..76e36a9 100644 --- a/ui/main_queue_processor.cpp +++ b/ui/main_queue_processor.cpp @@ -18,8 +18,10 @@ namespace Ui { namespace { -constexpr auto kProcessorEvent = QEvent::Type(QEvent::User + 1); -static_assert(kProcessorEvent < QEvent::MaxUser); +auto ProcessorEventType() { + static const auto Result = QEvent::Type(QEvent::registerEventType()); + return Result; +} QMutex ProcessorMutex; MainQueueProcessor *ProcessorInstance/* = nullptr*/; @@ -47,7 +49,7 @@ void PushToMainQueueGeneric(void (*callable)(void*), void *argument) { MainQueueProcessState.store(ProcessState::Waiting); } - auto event = std::make_unique(kProcessorEvent); + auto event = std::make_unique(ProcessorEventType()); QMutexLocker lock(&ProcessorMutex); if (ProcessorInstance) { @@ -94,7 +96,7 @@ MainQueueProcessor::MainQueueProcessor() { bool MainQueueProcessor::event(QEvent *event) { if constexpr (Platform::UseMainQueueGeneric()) { - if (event->type() == kProcessorEvent) { + if (event->type() == ProcessorEventType()) { DrainMainQueueGeneric(); return true; } diff --git a/ui/paint/arcs.cpp b/ui/paint/arcs.cpp index d3121d6..2f346e4 100644 --- a/ui/paint/arcs.cpp +++ b/ui/paint/arcs.cpp @@ -7,24 +7,10 @@ #include "ui/paint/arcs.h" #include "ui/effects/animation_value.h" +#include "ui/effects/animation_value_f.h" #include "ui/painter.h" namespace Ui::Paint { -namespace { - -inline float64 InterpolateF(float a, float b, float64 b_ratio) { - return a + float64(b - a) * b_ratio; -}; - -QRectF InterpolatedRect(const QRectF &r1, const QRectF &r2, float64 ratio) { - return QRectF( - InterpolateF(r1.x(), r2.x(), ratio), - InterpolateF(r1.y(), r2.y(), ratio), - InterpolateF(r1.width(), r2.width(), ratio), - InterpolateF(r1.height(), r2.height(), ratio)); -} - -} // namespace ArcsAnimation::ArcsAnimation( const style::ArcsAnimation &st, @@ -200,7 +186,7 @@ bool ArcsAnimation::isArcFinished(const Arc &arc) const { || ((arc.threshold <= _currentValue) && (arc.progress == 0.)); } -void ArcsAnimation::paint(Painter &p, std::optional colorOverride) { +void ArcsAnimation::paint(QPainter &p, std::optional colorOverride) { PainterHighQualityEnabler hq(p); QPen pen; if (_strokeRatio) { @@ -221,7 +207,7 @@ void ArcsAnimation::paint(Painter &p, std::optional colorOverride) { ? arc.rect : (progress == 1.) ? previousRect - : InterpolatedRect(arc.rect, previousRect, progress); + : anim::interpolatedRectF(arc.rect, previousRect, progress); p.drawArc(rect, _startAngle, _spanAngle); } p.setOpacity(1.); diff --git a/ui/paint/arcs.h b/ui/paint/arcs.h index 022b6d6..27d98bd 100644 --- a/ui/paint/arcs.h +++ b/ui/paint/arcs.h @@ -29,7 +29,7 @@ public: Direction direction); void paint( - Painter &p, + QPainter &p, std::optional colorOverride = std::nullopt); void setValue(float64 value); diff --git a/ui/paint/blob.cpp b/ui/paint/blob.cpp index c694ebc..5722659 100644 --- a/ui/paint/blob.cpp +++ b/ui/paint/blob.cpp @@ -82,7 +82,7 @@ RadialBlob::RadialBlob(int n, float minScale, float minSpeed, float maxSpeed) , _segments(n) { } -void RadialBlob::paint(Painter &p, const QBrush &brush, float outerScale) { +void RadialBlob::paint(QPainter &p, const QBrush &brush, float outerScale) { auto path = QPainterPath(); auto m = QTransform(); @@ -172,7 +172,7 @@ LinearBlob::LinearBlob( , _segments(_segmentsCount) { } -void LinearBlob::paint(Painter &p, const QBrush &brush, int width) { +void LinearBlob::paint(QPainter &p, const QBrush &brush, int width) { if (!width) { return; } diff --git a/ui/paint/blob.h b/ui/paint/blob.h index 805914b..4006d25 100644 --- a/ui/paint/blob.h +++ b/ui/paint/blob.h @@ -58,7 +58,7 @@ class RadialBlob final : public Blob { public: RadialBlob(int n, float minScale, float minSpeed = 0, float maxSpeed = 0); - void paint(Painter &p, const QBrush &brush, float outerScale = 1.); + void paint(QPainter &p, const QBrush &brush, float outerScale = 1.); void update(float level, float speedScale, float64 rate); private: @@ -94,7 +94,7 @@ public: float minSpeed = 0, float maxSpeed = 0); - void paint(Painter &p, const QBrush &brush, int width); + void paint(QPainter &p, const QBrush &brush, int width); private: struct Segment : Blob::Segment { diff --git a/ui/paint/blobs.cpp b/ui/paint/blobs.cpp index 903f5d9..00e2cb8 100644 --- a/ui/paint/blobs.cpp +++ b/ui/paint/blobs.cpp @@ -80,7 +80,7 @@ void Blobs::resetLevel() { _levelValue.reset(); } -void Blobs::paint(Painter &p, const QBrush &brush, float outerScale) { +void Blobs::paint(QPainter &p, const QBrush &brush, float outerScale) { const auto opacity = p.opacity(); for (auto i = 0; i < _blobs.size(); i++) { const auto alpha = _blobDatas[i].alpha; diff --git a/ui/paint/blobs.h b/ui/paint/blobs.h index c93f419..2dc446c 100644 --- a/ui/paint/blobs.h +++ b/ui/paint/blobs.h @@ -38,7 +38,7 @@ public: void setLevel(float value); void resetLevel(); - void paint(Painter &p, const QBrush &brush, float outerScale = 1.); + void paint(QPainter &p, const QBrush &brush, float outerScale = 1.); void updateLevel(crl::time dt); [[nodiscard]] float maxRadius() const; diff --git a/ui/paint/blobs_linear.cpp b/ui/paint/blobs_linear.cpp index 1f46e1f..4d274f2 100644 --- a/ui/paint/blobs_linear.cpp +++ b/ui/paint/blobs_linear.cpp @@ -78,7 +78,7 @@ void LinearBlobs::setLevel(float value) { _levelValue.start(to); } -void LinearBlobs::paint(Painter &p, const QBrush &brush, int width) { +void LinearBlobs::paint(QPainter &p, const QBrush &brush, int width) { PainterHighQualityEnabler hq(p); const auto opacity = p.opacity(); for (auto i = 0; i < _blobs.size(); i++) { diff --git a/ui/paint/blobs_linear.h b/ui/paint/blobs_linear.h index e175870..ea85f0e 100644 --- a/ui/paint/blobs_linear.h +++ b/ui/paint/blobs_linear.h @@ -9,8 +9,6 @@ #include "ui/effects/animation_value.h" #include "ui/paint/blob.h" -class Painter; - namespace Ui::Paint { class LinearBlobs final { @@ -38,7 +36,7 @@ public: Blob::Radiuses radiusesAt(int index); void setLevel(float value); - void paint(Painter &p, const QBrush &brush, int width); + void paint(QPainter &p, const QBrush &brush, int width); void updateLevel(crl::time dt); [[nodiscard]] float maxRadius() const; diff --git a/ui/painter.h b/ui/painter.h index 89389f0..dcc3f89 100644 --- a/ui/painter.h +++ b/ui/painter.h @@ -11,6 +11,10 @@ #include #include +namespace Ui::Text { +struct SpoilerMess; +} // namespace Ui::Text + class Painter : public QPainter { public: explicit Painter(QPaintDevice *device) : QPainter(device) { @@ -71,16 +75,33 @@ public: void restoreTextPalette() { _textPalette = nullptr; } - const style::TextPalette &textPalette() const { + [[nodiscard]] const style::TextPalette &textPalette() const { return _textPalette ? *_textPalette : st::defaultTextPalette; } + void setInactive(bool inactive) { + _inactive = inactive; + } + [[nodiscard]] bool inactive() const { + return _inactive; + } void setFont(const style::font &font) { _ascent = font->ascent; QPainter::setFont(font->f); } + void setTextSpoilerMess(not_null mess) { + _spoilerMess = mess; + } + void restoreTextSpoilerMess() { + _spoilerMess = nullptr; + } + [[nodiscard]] Ui::Text::SpoilerMess *textSpoilerMess() const { + return _spoilerMess; + } private: const style::TextPalette *_textPalette = nullptr; + Ui::Text::SpoilerMess *_spoilerMess = nullptr; + bool _inactive = false; int _ascent = 0; }; @@ -121,3 +142,30 @@ private: QPainter::RenderHints _hints; }; + +class ScopedPainterOpacity { +public: + ScopedPainterOpacity(QPainter &p, float64 nowOpacity) + : _painter(p) + , _wasOpacity(p.opacity()) { + if (_wasOpacity != nowOpacity) { + _painter.setOpacity(nowOpacity); + } + } + + ScopedPainterOpacity( + const ScopedPainterOpacity &other) = delete; + ScopedPainterOpacity &operator=( + const ScopedPainterOpacity &other) = delete; + + ~ScopedPainterOpacity() { + if (_painter.isActive()) { + _painter.setOpacity(_wasOpacity); + } + } + +private: + QPainter &_painter; + const float64 _wasOpacity; + +}; diff --git a/ui/platform/linux/ui_linux_wayland_integration.cpp b/ui/platform/linux/ui_linux_wayland_integration.cpp deleted file mode 100644 index 01f1e80..0000000 --- a/ui/platform/linux/ui_linux_wayland_integration.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* -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 "ui/platform/linux/ui_linux_wayland_integration.h" - -#include "base/platform/base_platform_info.h" -#include "waylandshells/xdg_shell.h" - -#include - -// private headers are using keywords :( -#ifdef QT_NO_KEYWORDS -#define signals Q_SIGNALS -#define slots Q_SLOTS -#endif // QT_NO_KEYWORDS - -#include -#include -#include -#include -#include - -#include -#include - -Q_DECLARE_METATYPE(QMargins); - -using QtWaylandClient::QWaylandIntegration; -using QtWaylandClient::QWaylandWindow; -using namespace KWayland::Client; - -namespace Ui { -namespace Platform { - -struct WaylandIntegration::Private { - std::unique_ptr connection; - Registry registry; - QEventLoop interfacesLoop; - bool interfacesAnnounced = false; -}; - -WaylandIntegration::WaylandIntegration() -: _private(std::make_unique()) { - _private->connection = std::unique_ptr{ - ConnectionThread::fromApplication(), - }; - - _private->registry.create(_private->connection.get()); - _private->registry.setup(); - - QObject::connect( - _private->connection.get(), - &ConnectionThread::connectionDied, - &_private->registry, - &Registry::destroy); - - QObject::connect( - &_private->registry, - &Registry::interfacesAnnounced, - [=] { - _private->interfacesAnnounced = true; - if (_private->interfacesLoop.isRunning()) { - _private->interfacesLoop.quit(); - } - }); -} - -WaylandIntegration::~WaylandIntegration() = default; - -WaylandIntegration *WaylandIntegration::Instance() { - if (!::Platform::IsWayland()) return nullptr; - static WaylandIntegration instance; - return &instance; -} - -void WaylandIntegration::waitForInterfaceAnnounce() { - Expects(!_private->interfacesLoop.isRunning()); - if (!_private->interfacesAnnounced) { - _private->interfacesLoop.exec(); - } -} - -bool WaylandIntegration::xdgDecorationSupported() { - return _private->registry.hasInterface( - Registry::Interface::XdgDecorationUnstableV1); -} - -bool WaylandIntegration::windowExtentsSupported() { - // initialize shell integration before querying - if (const auto integration = static_cast( - QGuiApplicationPrivate::platformIntegration())) { - integration->shellIntegration(); - } - return WaylandShells::XdgShell(); -} - -void WaylandIntegration::setWindowExtents( - QWindow *window, - const QMargins &extents) { - window->setProperty( - "_desktopApp_waylandCustomMargins", - QVariant::fromValue(extents)); -} - -void WaylandIntegration::unsetWindowExtents(QWindow *window) { - window->setProperty( - "_desktopApp_waylandCustomMargins", - QVariant()); -} - -bool WaylandIntegration::showWindowMenu(QWindow *window) { - if (const auto waylandWindow = static_cast( - window->handle())) { - if (const auto seat = waylandWindow->display()->lastInputDevice()) { - if (const auto shellSurface = waylandWindow->shellSurface()) { - return shellSurface->showWindowMenu(seat); - } - } - } - - return false; -} - -} // namespace Platform -} // namespace Ui diff --git a/ui/platform/linux/ui_linux_wayland_integration.h b/ui/platform/linux/ui_linux_wayland_integration.h deleted file mode 100644 index c975539..0000000 --- a/ui/platform/linux/ui_linux_wayland_integration.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -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 QWindow; - -namespace Ui { -namespace Platform { - -class WaylandIntegration { -public: - [[nodiscard]] static WaylandIntegration *Instance(); - - void waitForInterfaceAnnounce(); - [[nodiscard]] bool xdgDecorationSupported(); - [[nodiscard]] bool windowExtentsSupported(); - void setWindowExtents(QWindow *window, const QMargins &extents); - void unsetWindowExtents(QWindow *window); - bool showWindowMenu(QWindow *window); - -private: - WaylandIntegration(); - ~WaylandIntegration(); - - struct Private; - const std::unique_ptr _private; -}; - -} // namespace Platform -} // namespace Ui diff --git a/ui/platform/linux/ui_linux_wayland_integration_dummy.cpp b/ui/platform/linux/ui_linux_wayland_integration_dummy.cpp deleted file mode 100644 index 0239433..0000000 --- a/ui/platform/linux/ui_linux_wayland_integration_dummy.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -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 "ui/platform/linux/ui_linux_wayland_integration.h" - -#include "base/platform/base_platform_info.h" - -namespace Ui { -namespace Platform { - -struct WaylandIntegration::Private { -}; - -WaylandIntegration::WaylandIntegration() { -} - -WaylandIntegration::~WaylandIntegration() = default; - -WaylandIntegration *WaylandIntegration::Instance() { - if (!::Platform::IsWayland()) return nullptr; - static WaylandIntegration instance; - return &instance; -} - -void WaylandIntegration::waitForInterfaceAnnounce() { -} - -bool WaylandIntegration::xdgDecorationSupported() { - return false; -} - -bool WaylandIntegration::windowExtentsSupported() { - return false; -} - -void WaylandIntegration::setWindowExtents( - QWindow *window, - const QMargins &extents) { -} - -void WaylandIntegration::unsetWindowExtents(QWindow *window) { -} - -bool WaylandIntegration::showWindowMenu(QWindow *window) { - return false; -} - -} // namespace Platform -} // namespace Ui diff --git a/ui/platform/linux/ui_utility_linux.cpp b/ui/platform/linux/ui_utility_linux.cpp index f55ed32..eda2916 100644 --- a/ui/platform/linux/ui_utility_linux.cpp +++ b/ui/platform/linux/ui_utility_linux.cpp @@ -7,28 +7,44 @@ #include "ui/platform/linux/ui_utility_linux.h" #include "base/platform/base_platform_info.h" -#include "ui/platform/linux/ui_linux_wayland_integration.h" -#include "base/const_string.h" - -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION -#include "base/platform/linux/base_linux_glibmm_helper.h" -#include "base/platform/linux/base_linux_xdp_utilities.h" -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION +#include "base/platform/linux/base_linux_library.h" #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION #include "base/platform/linux/base_linux_xcb_utilities.h" -#include "base/platform/linux/base_linux_xsettings.h" #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION #include #include #include +#include +#include + +extern "C" { + +typedef int32_t wl_fixed_t; +struct wl_object; +struct wl_array; +struct wl_proxy; +struct xdg_toplevel; + +union wl_argument { + int32_t i; /**< `int` */ + uint32_t u; /**< `uint` */ + wl_fixed_t f; /**< `fixed` */ + const char *s; /**< `string` */ + struct wl_object *o; /**< `object` */ + uint32_t n; /**< `new_id` */ + struct wl_array *a; /**< `array` */ + int32_t h; /**< `fd` */ +}; + +} namespace Ui { namespace Platform { namespace { -constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs; +static const auto kXCBFrameExtentsAtomName = u"_GTK_FRAME_EXTENTS"_q; #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION std::optional XCBWindowMapped(xcb_window_t window) { @@ -208,7 +224,7 @@ std::optional XCBWindowWorkspace(xcb_window_t window) { std::optional XCBIsOverlapped( not_null widget, const QRect &rect) { - const auto window = widget->window()->winId(); + const auto window = widget->winId(); Expects(window != XCB_WINDOW_NONE); const auto connection = base::Platform::XCB::GetConnectionFromQt(); @@ -221,11 +237,8 @@ std::optional XCBIsOverlapped( return std::nullopt; } - const auto windowWorkspace = XCBWindowWorkspace( - window); - + const auto windowWorkspace = XCBWindowWorkspace(window); const auto currentWorkspace = XCBCurrentWorkspace(); - if (windowWorkspace.has_value() && currentWorkspace.has_value() && *windowWorkspace != *currentWorkspace @@ -233,6 +246,17 @@ std::optional XCBIsOverlapped( return true; } + const auto windowGeometry = XCBWindowGeometry(window); + if (windowGeometry.isNull()) { + return std::nullopt; + } + + const auto mappedRect = QRect( + rect.topLeft() + * widget->windowHandle()->devicePixelRatio() + + windowGeometry.topLeft(), + rect.size() * widget->windowHandle()->devicePixelRatio()); + const auto cookie = xcb_query_tree(connection, *root); const auto reply = base::Platform::XCB::MakeReplyPointer( xcb_query_tree_reply(connection, cookie, nullptr)); @@ -255,7 +279,7 @@ std::optional XCBIsOverlapped( } const auto geometry = XCBWindowGeometry(tree[i]); - if (!rect.intersects(geometry)) { + if (!mappedRect.intersects(geometry)) { continue; } @@ -283,7 +307,7 @@ std::optional XCBIsOverlapped( return false; } -void SetXCBFrameExtents(QWindow *window, const QMargins &extents) { +void SetXCBFrameExtents(not_null widget, const QMargins &extents) { const auto connection = base::Platform::XCB::GetConnectionFromQt(); if (!connection) { return; @@ -291,23 +315,26 @@ void SetXCBFrameExtents(QWindow *window, const QMargins &extents) { const auto frameExtentsAtom = base::Platform::XCB::GetAtom( connection, - kXCBFrameExtentsAtomName.utf16()); + kXCBFrameExtentsAtomName); if (!frameExtentsAtom.has_value()) { return; } + const auto nativeExtents = extents + * widget->windowHandle()->devicePixelRatio(); + const auto extentsVector = std::vector{ - uint(extents.left()), - uint(extents.right()), - uint(extents.top()), - uint(extents.bottom()), + uint(nativeExtents.left()), + uint(nativeExtents.right()), + uint(nativeExtents.top()), + uint(nativeExtents.bottom()), }; xcb_change_property( connection, XCB_PROP_MODE_REPLACE, - window->winId(), + widget->winId(), *frameExtentsAtom, XCB_ATOM_CARDINAL, 32, @@ -315,7 +342,7 @@ void SetXCBFrameExtents(QWindow *window, const QMargins &extents) { extentsVector.data()); } -void UnsetXCBFrameExtents(QWindow *window) { +void UnsetXCBFrameExtents(not_null widget) { const auto connection = base::Platform::XCB::GetConnectionFromQt(); if (!connection) { return; @@ -323,7 +350,7 @@ void UnsetXCBFrameExtents(QWindow *window) { const auto frameExtentsAtom = base::Platform::XCB::GetAtom( connection, - kXCBFrameExtentsAtomName.utf16()); + kXCBFrameExtentsAtomName); if (!frameExtentsAtom.has_value()) { return; @@ -331,19 +358,19 @@ void UnsetXCBFrameExtents(QWindow *window) { xcb_delete_property( connection, - window->winId(), + widget->winId(), *frameExtentsAtom); } -bool ShowXCBWindowMenu(QWindow *window) { +void ShowXCBWindowMenu(not_null widget, const QPoint &point) { const auto connection = base::Platform::XCB::GetConnectionFromQt(); if (!connection) { - return false; + return; } const auto root = base::Platform::XCB::GetRootWindow(connection); if (!root.has_value()) { - return false; + return; } const auto showWindowMenuAtom = base::Platform::XCB::GetAtom( @@ -351,16 +378,23 @@ bool ShowXCBWindowMenu(QWindow *window) { "_GTK_SHOW_WINDOW_MENU"); if (!showWindowMenuAtom.has_value()) { - return false; + return; } - const auto globalPos = QCursor::pos(); + const auto windowGeometry = XCBWindowGeometry(widget->winId()); + if (windowGeometry.isNull()) { + return; + } + + const auto globalPos = point + * widget->windowHandle()->devicePixelRatio() + + windowGeometry.topLeft(); xcb_client_message_event_t xev; xev.response_type = XCB_CLIENT_MESSAGE; xev.type = *showWindowMenuAtom; xev.sequence = 0; - xev.window = window->winId(); + xev.window = widget->winId(); xev.format = 32; xev.data.data32[0] = 0; xev.data.data32[1] = globalPos.x(); @@ -376,45 +410,56 @@ bool ShowXCBWindowMenu(QWindow *window) { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, reinterpret_cast(&xev)); - - return true; } #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION -TitleControls::Control GtkKeywordToTitleControl(const QString &keyword) { - if (keyword == qstr("minimize")) { - return TitleControls::Control::Minimize; - } else if (keyword == qstr("maximize")) { - return TitleControls::Control::Maximize; - } else if (keyword == qstr("close")) { - return TitleControls::Control::Close; +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) +void ShowWaylandWindowMenu(not_null widget, const QPoint &point) { + static const auto wl_proxy_marshal_array = [] { + void (*result)( + struct wl_proxy *p, + uint32_t opcode, + union wl_argument *args) = nullptr; + + if (const auto lib = base::Platform::LoadLibrary( + "libwayland-client.so.0", + RTLD_NODELETE)) { + base::Platform::LoadSymbol(lib, "wl_proxy_marshal_array", result); + } + + return result; + }(); + + if (!wl_proxy_marshal_array) { + return; } - return TitleControls::Control::Unknown; -} - -TitleControls::Layout GtkKeywordsToTitleControlsLayout(const QString &keywords) { - const auto splitted = keywords.split(':'); - - std::vector controlsLeft; - ranges::transform( - splitted[0].split(','), - ranges::back_inserter(controlsLeft), - GtkKeywordToTitleControl); - - std::vector controlsRight; - if (splitted.size() > 1) { - ranges::transform( - splitted[1].split(','), - ranges::back_inserter(controlsRight), - GtkKeywordToTitleControl); + using namespace QNativeInterface; + using namespace QNativeInterface::Private; + const auto window = not_null(widget->windowHandle()); + const auto native = qApp->nativeInterface(); + const auto nativeWindow = window->nativeInterface(); + if (!native || !nativeWindow) { + return; } - return TitleControls::Layout{ - .left = controlsLeft, - .right = controlsRight - }; + const auto toplevel = nativeWindow->surfaceRole(); + const auto seat = native->lastInputSeat(); + if (!toplevel || !seat) { + return; + } + + wl_proxy_marshal_array( + reinterpret_cast(toplevel), + 4, // XDG_TOPLEVEL_SHOW_WINDOW_MENU + std::array{ + wl_argument{ .o = reinterpret_cast(seat) }, + wl_argument{ .u = native->lastInputSerial() }, + wl_argument{ .i = point.x() }, + wl_argument{ .i = point.y() }, + }.data()); } +#endif // Qt >= 6.5.0 } // namespace @@ -422,7 +467,7 @@ bool IsApplicationActive() { return QApplication::activeWindow() != nullptr; } -bool TranslucentWindowsSupported(QPoint globalPosition) { +bool TranslucentWindowsSupported() { if (::Platform::IsWayland()) { return true; } @@ -487,15 +532,26 @@ std::optional IsOverlapped( return std::nullopt; } -bool WindowExtentsSupported() { - if (const auto integration = WaylandIntegration::Instance()) { - return integration->windowExtentsSupported(); +bool WindowMarginsSupported() { +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + static const auto WaylandResult = [] { + using namespace QNativeInterface::Private; + QWindow window; + window.create(); + return bool(window.nativeInterface()); + }(); + + if (WaylandResult) { + return true; } +#endif // Qt >= 6.5.0 #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION namespace XCB = base::Platform::XCB; if (::Platform::IsX11() - && XCB::IsSupportedByWM(kXCBFrameExtentsAtomName.utf16())) { + && XCB::IsSupportedByWM( + XCB::GetConnectionFromQt(), + kXCBFrameExtentsAtomName)) { return true; } #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION @@ -503,140 +559,66 @@ bool WindowExtentsSupported() { return false; } -void SetWindowExtents(QWindow *window, const QMargins &extents) { - if (const auto integration = WaylandIntegration::Instance()) { - integration->setWindowExtents(window, extents); - } else if (::Platform::IsX11()) { -#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION - SetXCBFrameExtents(window, extents); -#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION +void SetWindowMargins(not_null widget, const QMargins &margins) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + using namespace QNativeInterface::Private; + const auto window = not_null(widget->windowHandle()); + const auto platformWindow = not_null(window->handle()); + if (const auto native = window->nativeInterface()) { + native->setCustomMargins( + margins + * window->devicePixelRatio() + / platformWindow->devicePixelRatio()); + return; } +#endif // Qt >= 6.5.0 + +#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION + if (::Platform::IsX11()) { + SetXCBFrameExtents(widget, margins); + return; + } +#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION } -void UnsetWindowExtents(QWindow *window) { - if (const auto integration = WaylandIntegration::Instance()) { - integration->unsetWindowExtents(window); - } else if (::Platform::IsX11()) { -#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION - UnsetXCBFrameExtents(window); -#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION +void UnsetWindowMargins(not_null widget) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + using namespace QNativeInterface::Private; + if (const auto native = not_null(widget->windowHandle()) + ->nativeInterface()) { + native->setCustomMargins(QMargins()); + return; } +#endif // Qt >= 6.5.0 + +#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION + if (::Platform::IsX11()) { + UnsetXCBFrameExtents(widget); + return; + } +#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION } -bool ShowWindowMenu(QWindow *window) { - if (const auto integration = WaylandIntegration::Instance()) { - return integration->showWindowMenu(window); - } else if (::Platform::IsX11()) { -#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION - return ShowXCBWindowMenu(window); -#else // !DESKTOP_APP_DISABLE_X11_INTEGRATION - return false; -#endif // DESKTOP_APP_DISABLE_X11_INTEGRATION +void ShowWindowMenu(not_null widget, const QPoint &point) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + if (::Platform::IsWayland()) { + ShowWaylandWindowMenu(widget, point); + return; } +#endif // Qt >= 6.5.0 - return false; +#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION + if (::Platform::IsX11()) { + ShowXCBWindowMenu(widget, point); + return; + } +#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION } -TitleControls::Layout TitleControlsLayout() { - [[maybe_unused]] static const auto Inited = [] { -#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION - using base::Platform::XCB::XSettings; - if (const auto xSettings = XSettings::Instance()) { - xSettings->registerCallbackForProperty("Gtk/DecorationLayout", []( - xcb_connection_t *, - const QByteArray &, - const QVariant &, - void *) { - NotifyTitleControlsLayoutChanged(); - }, nullptr); - } -#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION - -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - using XDPSettingWatcher = base::Platform::XDP::SettingWatcher; - static const XDPSettingWatcher settingWatcher( - [=]( - const Glib::ustring &group, - const Glib::ustring &key, - const Glib::VariantBase &value) { - if (group == "org.gnome.desktop.wm.preferences" - && key == "button-layout") { - NotifyTitleControlsLayoutChanged(); - } - }); -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION - - return true; - }(); - -#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION - const auto xSettingsResult = []() -> std::optional { - using base::Platform::XCB::XSettings; - const auto xSettings = XSettings::Instance(); - if (!xSettings) { - return std::nullopt; - } - - const auto decorationLayout = xSettings->setting("Gtk/DecorationLayout"); - if (!decorationLayout.isValid()) { - return std::nullopt; - } - - return GtkKeywordsToTitleControlsLayout(decorationLayout.toString()); - }(); - - if (xSettingsResult.has_value()) { - return *xSettingsResult; - } -#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION - -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - const auto portalResult = []() -> std::optional { - try { - using namespace base::Platform::XDP; - - const auto decorationLayout = ReadSetting( - "org.gnome.desktop.wm.preferences", - "button-layout"); - - if (!decorationLayout.has_value()) { - return std::nullopt; - } - - return GtkKeywordsToTitleControlsLayout( - QString::fromStdString( - base::Platform::GlibVariantCast( - *decorationLayout))); - } catch (...) { - } - - return std::nullopt; - }(); - - if (portalResult.has_value()) { - return *portalResult; - } -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION - -#ifdef __HAIKU__ - return TitleControls::Layout{ - .left = { - TitleControls::Control::Close, - }, - .right = { - TitleControls::Control::Minimize, - TitleControls::Control::Maximize, - } - }; -#else // __HAIKU__ - return TitleControls::Layout{ - .right = { - TitleControls::Control::Minimize, - TitleControls::Control::Maximize, - TitleControls::Control::Close, - } - }; -#endif // !__HAIKU__ +void SetGeometryWithPossibleScreenChange( + not_null widget, + QRect geometry) { + widget->setGeometry(geometry); } } // namespace Platform diff --git a/ui/platform/linux/ui_utility_linux.h b/ui/platform/linux/ui_utility_linux.h index c6be70e..605fecb 100644 --- a/ui/platform/linux/ui_utility_linux.h +++ b/ui/platform/linux/ui_utility_linux.h @@ -23,18 +23,21 @@ inline void DeInitOnTopPanel(not_null panel) { inline void ReInitOnTopPanel(not_null panel) { } -inline void UpdateOverlayed(not_null widget) { -} - inline void ShowOverAll(not_null widget, bool canFocus) { } -inline void BringToBack(not_null widget) { +inline void AcceptAllMouseInput(not_null widget) { +} + +inline void DisableSystemWindowResize(not_null widget, QSize ratio) { } inline constexpr bool UseMainQueueGeneric() { return true; } +inline void FixPopupMenuNativeEmojiPopup(not_null menu) { +} + } // namespace Platform } // namespace Ui diff --git a/ui/platform/linux/ui_window_linux.cpp b/ui/platform/linux/ui_window_linux.cpp index a353c32..7a3aa25 100644 --- a/ui/platform/linux/ui_window_linux.cpp +++ b/ui/platform/linux/ui_window_linux.cpp @@ -6,8 +6,6 @@ // #include "ui/platform/linux/ui_window_linux.h" -#include "ui/platform/linux/ui_linux_wayland_integration.h" - namespace Ui { namespace Platform { @@ -17,9 +15,7 @@ std::unique_ptr CreateSpecialWindowHelper( } bool NativeWindowFrameSupported() { - const auto waylandIntegration = WaylandIntegration::Instance(); - return !waylandIntegration - || waylandIntegration->xdgDecorationSupported(); + return true; } } // namespace Platform diff --git a/ui/platform/linux/ui_window_title_linux.cpp b/ui/platform/linux/ui_window_title_linux.cpp new file mode 100644 index 0000000..ba1a331 --- /dev/null +++ b/ui/platform/linux/ui_window_title_linux.cpp @@ -0,0 +1,136 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/platform/linux/ui_window_title_linux.h" + +#include "base/platform/linux/base_linux_xdp_utilities.h" + +#include "base/integration.h" + +#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION +#include "base/platform/linux/base_linux_xsettings.h" +#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION + +namespace Ui { +namespace Platform { +namespace internal { +namespace { + +TitleControls::Control GtkKeywordToTitleControl(const QString &keyword) { + if (keyword == qstr("minimize")) { + return TitleControls::Control::Minimize; + } else if (keyword == qstr("maximize")) { + return TitleControls::Control::Maximize; + } else if (keyword == qstr("close")) { + return TitleControls::Control::Close; + } + + return TitleControls::Control::Unknown; +} + +TitleControls::Layout GtkKeywordsToTitleControlsLayout(const QString &keywords) { + const auto splitted = keywords.split(':'); + + std::vector controlsLeft; + ranges::transform( + splitted[0].split(','), + ranges::back_inserter(controlsLeft), + GtkKeywordToTitleControl); + + std::vector controlsRight; + if (splitted.size() > 1) { + ranges::transform( + splitted[1].split(','), + ranges::back_inserter(controlsRight), + GtkKeywordToTitleControl); + } + + return TitleControls::Layout{ + .left = controlsLeft, + .right = controlsRight, + }; +} + +} // namespace + +TitleControls::Layout TitleControlsLayout() { + [[maybe_unused]] static const auto Inited = [] { +#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION + using base::Platform::XCB::XSettings; + if (const auto xSettings = XSettings::Instance()) { + xSettings->registerCallbackForProperty("Gtk/DecorationLayout", []( + xcb_connection_t *, + const QByteArray &, + const QVariant &, + void *) { + NotifyTitleControlsLayoutChanged(); + }, nullptr); + } +#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION + + namespace XDP = base::Platform::XDP; + static const XDP::SettingWatcher settingWatcher( + "org.gnome.desktop.wm.preferences", + "button-layout", + [] { + base::Integration::Instance().enterFromEventLoop([] { + NotifyTitleControlsLayoutChanged(); + }); + }); + + return true; + }(); + +#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION + const auto xSettingsResult = []() -> std::optional { + using base::Platform::XCB::XSettings; + const auto xSettings = XSettings::Instance(); + if (!xSettings) { + return std::nullopt; + } + + const auto decorationLayout = xSettings->setting("Gtk/DecorationLayout"); + if (!decorationLayout.isValid()) { + return std::nullopt; + } + + return GtkKeywordsToTitleControlsLayout(decorationLayout.toString()); + }(); + + if (xSettingsResult.has_value()) { + return *xSettingsResult; + } +#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION + + const auto portalResult = []() -> std::optional { + auto decorationLayout = base::Platform::XDP::ReadSetting( + "org.gnome.desktop.wm.preferences", + "button-layout"); + + if (!decorationLayout.has_value()) { + return std::nullopt; + } + + return GtkKeywordsToTitleControlsLayout( + QString::fromStdString(decorationLayout->get_string(nullptr))); + }(); + + if (portalResult.has_value()) { + return *portalResult; + } + + return TitleControls::Layout{ + .right = { + TitleControls::Control::Minimize, + TitleControls::Control::Maximize, + TitleControls::Control::Close, + } + }; +} + +} // namespace internal +} // namespace Platform +} // namespace Ui diff --git a/ui/platform/linux/ui_window_title_linux.h b/ui/platform/linux/ui_window_title_linux.h new file mode 100644 index 0000000..0aa287b --- /dev/null +++ b/ui/platform/linux/ui_window_title_linux.h @@ -0,0 +1,9 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +#include "ui/platform/ui_platform_window_title.h" diff --git a/ui/platform/mac/ui_utility_mac.h b/ui/platform/mac/ui_utility_mac.h index de4787b..4d37327 100644 --- a/ui/platform/mac/ui_utility_mac.h +++ b/ui/platform/mac/ui_utility_mac.h @@ -13,13 +13,10 @@ namespace Ui { namespace Platform { -inline bool TranslucentWindowsSupported(QPoint globalPosition) { +inline bool TranslucentWindowsSupported() { return true; } -inline void UpdateOverlayed(not_null widget) { -} - inline void ClearTransientParent(not_null widget) { } @@ -27,18 +24,20 @@ inline constexpr bool UseMainQueueGeneric() { return ::Platform::IsMacStoreBuild(); } -inline bool WindowExtentsSupported() { +inline bool WindowMarginsSupported() { return false; } -inline void SetWindowExtents(QWindow *window, const QMargins &extents) { +inline void SetWindowMargins(not_null widget, const QMargins &margins) { } -inline void UnsetWindowExtents(QWindow *window) { +inline void UnsetWindowMargins(not_null widget) { } -inline bool ShowWindowMenu(QWindow *window) { - return false; +inline void ShowWindowMenu(not_null widget, const QPoint &point) { +} + +inline void FixPopupMenuNativeEmojiPopup(not_null menu) { } } // namespace Platform diff --git a/ui/platform/mac/ui_utility_mac.mm b/ui/platform/mac/ui_utility_mac.mm index b230169..02bc70b 100644 --- a/ui/platform/mac/ui_utility_mac.mm +++ b/ui/platform/mac/ui_utility_mac.mm @@ -72,14 +72,26 @@ void ShowOverAll(not_null widget, bool canFocus) { NSWindow *wnd = [reinterpret_cast(widget->winId()) window]; [wnd setLevel:NSPopUpMenuWindowLevel]; if (!canFocus) { - [wnd setStyleMask:NSUtilityWindowMask | NSNonactivatingPanelMask]; + [wnd setStyleMask:NSWindowStyleMaskUtilityWindow | NSWindowStyleMaskNonactivatingPanel]; [wnd setCollectionBehavior:NSWindowCollectionBehaviorMoveToActiveSpace|NSWindowCollectionBehaviorStationary|NSWindowCollectionBehaviorFullScreenAuxiliary|NSWindowCollectionBehaviorIgnoresCycle]; } } -void BringToBack(not_null widget) { - NSWindow *wnd = [reinterpret_cast(widget->winId()) window]; - [wnd setLevel:NSModalPanelWindowLevel]; +void AcceptAllMouseInput(not_null widget) { + // https://github.com/telegramdesktop/tdesktop/issues/27025 + // + // By default system clicks through fully transparent pixels, + // and starting with macOS 14.1 it counts the transparency + // incorrectly (as if `y` is mirrored), so when clicking + // on a reactions strip outside of the menu column the click + // is ignored and made on the underlying window, because at the + // bottom of the menu in the same place there is nothing, empty. + // + // We explicitly request all the input to disable this behavior. + // + // See https://stackoverflow.com/a/29451199 and comments. + NSWindow *window = [reinterpret_cast(widget->winId()) window]; + [window setIgnoresMouseEvents:NO]; } void DrainMainQueue() { @@ -91,21 +103,28 @@ void DrainMainQueue() { void IgnoreAllActivation(not_null widget) { } +void DisableSystemWindowResize(not_null widget, QSize ratio) { + const auto winId = widget->winId(); + if (const auto view = reinterpret_cast(winId)) { + if (const auto window = [view window]) { + window.styleMask &= ~NSWindowStyleMaskResizable; + } + } +} + std::optional IsOverlapped( not_null widget, const QRect &rect) { - NSWindow *window = [reinterpret_cast(widget->window()->winId()) window]; + NSWindow *window = [reinterpret_cast(widget->winId()) window]; Assert(window != nullptr); if (![window isOnActiveSpace]) { return true; } - const auto nativeRect = CGRectMake( - rect.x(), - rect.y(), - rect.width(), - rect.height()); + const auto nativeRect = QRect( + widget->mapToGlobal(rect.topLeft()), + rect.size()).toCGRect(); CGWindowID windowId = (CGWindowID)[window windowNumber]; const CGWindowListOption options = kCGWindowListExcludeDesktopElements @@ -145,14 +164,10 @@ std::optional IsOverlapped( return false; } -TitleControls::Layout TitleControlsLayout() { - return TitleControls::Layout{ - .left = { - TitleControls::Control::Close, - TitleControls::Control::Minimize, - TitleControls::Control::Maximize, - } - }; +void SetGeometryWithPossibleScreenChange( + not_null widget, + QRect geometry) { + widget->setGeometry(geometry); } } // namespace Platform diff --git a/ui/platform/mac/ui_window_mac.h b/ui/platform/mac/ui_window_mac.h index dd5b9bd..e3da674 100644 --- a/ui/platform/mac/ui_window_mac.h +++ b/ui/platform/mac/ui_window_mac.h @@ -28,6 +28,8 @@ public: void setGeometry(QRect rect) override; void close() override; + const style::TextStyle &titleTextStyle() const override; + private: class Private; friend class Private; diff --git a/ui/platform/mac/ui_window_mac.mm b/ui/platform/mac/ui_window_mac.mm index 365ffcc..7b29363 100644 --- a/ui/platform/mac/ui_window_mac.mm +++ b/ui/platform/mac/ui_window_mac.mm @@ -105,7 +105,10 @@ public: _dragStarted = _checkStartDrag(); } else if (([e type] == NSEventTypeLeftMouseDragged) && _dragStarted) { - return _checkPerformDrag([e window]); + if (_checkPerformDrag([e window])) { + return true; + } + _dragStarted = false; } } return false; @@ -130,12 +133,14 @@ public: [[nodiscard]] bool checkNativeMove(void *nswindow) const; void activateBeforeNativeMove(); void setStaysOnTop(bool enabled); + void setNativeTitleVisibility(bool visible); void close(); private: void init(); void initOpenGL(); void resolveWeakPointers(); + void revalidateWeakPointers() const; void initCustomTitle(); [[nodiscard]] Fn toggleCustomTitleCallback(); @@ -147,6 +152,7 @@ private: NSWindow * __weak _nativeWindow = nil; NSView * __weak _nativeView = nil; + bool _hadNativeValues = false; std::unique_ptr _layerCreationChecker; @@ -170,6 +176,7 @@ int WindowHelper::Private::customTitleHeight() const { } QRect WindowHelper::Private::controlsRect() const { + revalidateWeakPointers(); const auto button = [&](NSWindowButton type) { auto view = [_nativeWindow standardWindowButton:type]; if (!view) { @@ -200,8 +207,9 @@ QRect WindowHelper::Private::controlsRect() const { } bool WindowHelper::Private::checkNativeMove(void *nswindow) const { + revalidateWeakPointers(); if (_nativeWindow != nswindow - || ([_nativeWindow styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask) { + || ([_nativeWindow styleMask] & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) { return false; } const auto cgReal = [NSEvent mouseLocation]; @@ -213,6 +221,7 @@ bool WindowHelper::Private::checkNativeMove(void *nswindow) const { } void WindowHelper::Private::activateBeforeNativeMove() { + revalidateWeakPointers(); [_nativeWindow makeKeyAndOrderFront:_nativeWindow]; } @@ -220,13 +229,27 @@ void WindowHelper::Private::setStaysOnTop(bool enabled) { _owner->BasicWindowHelper::setStaysOnTop(enabled); resolveWeakPointers(); initCustomTitle(); + _owner->updateCustomTitleVisibility(true); +} + +void WindowHelper::Private::setNativeTitleVisibility(bool visible) { + revalidateWeakPointers(); + if (!_nativeWindow) { + return; + } + const auto value = visible ? NSWindowTitleVisible : NSWindowTitleHidden; + [_nativeWindow setTitleVisibility:value]; } void WindowHelper::Private::close() { const auto weak = Ui::MakeWeak(_owner->window()); QCloseEvent e; qApp->sendEvent(_owner->window(), &e); - if (e.isAccepted() && weak && _nativeWindow) { + if (!e.isAccepted() || !weak) { + return; + } + revalidateWeakPointers(); + if (_nativeWindow) { [_nativeWindow close]; } } @@ -243,8 +266,9 @@ Fn WindowHelper::Private::enforceStyleCallback() { } void WindowHelper::Private::enforceStyle() { + revalidateWeakPointers(); if (_nativeWindow && _customTitleHeight > 0) { - [_nativeWindow setStyleMask:[_nativeWindow styleMask] | NSFullSizeContentViewWindowMask]; + [_nativeWindow setStyleMask:[_nativeWindow styleMask] | NSWindowStyleMaskFullSizeContentView]; } } @@ -253,14 +277,24 @@ void WindowHelper::Private::initOpenGL() { } void WindowHelper::Private::resolveWeakPointers() { - _owner->window()->createWinId(); + if (!_owner->window()->winId()) { + _owner->window()->createWinId(); + } _nativeView = reinterpret_cast(_owner->window()->winId()); _nativeWindow = _nativeView ? [_nativeView window] : nullptr; + _hadNativeValues = true; Ensures(_nativeWindow != nullptr); } +void WindowHelper::Private::revalidateWeakPointers() const { + if (_nativeWindow || !_hadNativeValues) { + return; + } + const_cast(this)->resolveWeakPointers(); +} + void WindowHelper::Private::initCustomTitle() { if (![_nativeWindow respondsToSelector:@selector(contentLayoutRect)] || ![_nativeWindow respondsToSelector:@selector(setTitlebarAppearsTransparent:)]) { @@ -282,7 +316,7 @@ void WindowHelper::Private::initCustomTitle() { // Emulate custom title instead (code below). // // Tried to backport a fix, testing. - [_nativeWindow setStyleMask:[_nativeWindow styleMask] | NSFullSizeContentViewWindowMask]; + [_nativeWindow setStyleMask:[_nativeWindow styleMask] | NSWindowStyleMaskFullSizeContentView]; auto inner = [_nativeWindow contentLayoutRect]; auto full = [_nativeView frame]; _customTitleHeight = qMax(qRound(full.size.height - inner.size.height), 0); @@ -316,10 +350,8 @@ WindowHelper::WindowHelper(not_null window) window.get(), _private->customTitleHeight())) , _body(Ui::CreateChild(window.get())) { - if (_title->shouldBeHidden()) { - updateCustomTitleVisibility(); - } init(); + _title->setControlsRect(_private->controlsRect()); } WindowHelper::~WindowHelper() { @@ -336,14 +368,12 @@ QMargins WindowHelper::frameMargins() { void WindowHelper::setTitle(const QString &title) { _title->setText(title); - window()->setWindowTitle(_titleVisible ? QString() : title); + window()->setWindowTitle(title); } void WindowHelper::setTitleStyle(const style::WindowTitle &st) { _title->setStyle(st); - if (_title->shouldBeHidden()) { - updateCustomTitleVisibility(); - } + updateCustomTitleVisibility(); } void WindowHelper::updateCustomTitleVisibility(bool force) { @@ -352,15 +382,15 @@ void WindowHelper::updateCustomTitleVisibility(bool force) { return; } _title->setVisible(visible); - window()->setWindowTitle(_titleVisible ? QString() : _title->text()); + _private->setNativeTitleVisibility(!_titleVisible); } void WindowHelper::setMinimumSize(QSize size) { - window()->setMinimumSize(size.width(), _title->height() + size.height()); + window()->setMinimumSize(size.width(), frameMargins().top() + size.height()); } void WindowHelper::setFixedSize(QSize size) { - window()->setFixedSize(size.width(), _title->height() + size.height()); + window()->setFixedSize(size.width(), frameMargins().top() + size.height()); } void WindowHelper::setStaysOnTop(bool enabled) { @@ -368,7 +398,7 @@ void WindowHelper::setStaysOnTop(bool enabled) { } void WindowHelper::setGeometry(QRect rect) { - window()->setGeometry(rect.marginsAdded({ 0, _title->height(), 0, 0 })); + window()->setGeometry(rect.marginsAdded(frameMargins())); } void WindowHelper::setupBodyTitleAreaEvents() { @@ -393,7 +423,13 @@ void WindowHelper::close() { _private->close(); } +const style::TextStyle &WindowHelper::titleTextStyle() const { + return _title->textStyle(); +} + void WindowHelper::init() { + updateCustomTitleVisibility(true); + style::PaletteChanged( ) | rpl::start_with_next([=] { Ui::ForceFullRepaint(window()); diff --git a/ui/platform/mac/ui_window_title_mac.h b/ui/platform/mac/ui_window_title_mac.h index 3aac917..9b1b097 100644 --- a/ui/platform/mac/ui_window_title_mac.h +++ b/ui/platform/mac/ui_window_title_mac.h @@ -6,6 +6,7 @@ // #pragma once +#include "ui/text/text.h" #include "ui/rp_widget.h" #include "base/object_ptr.h" @@ -14,6 +15,7 @@ namespace style { struct WindowTitle; +struct TextStyle; } // namespace style namespace Ui { @@ -25,11 +27,14 @@ namespace Platform { class TitleWidget : public RpWidget { public: TitleWidget(not_null parent, int height); + ~TitleWidget(); void setText(const QString &text); void setStyle(const style::WindowTitle &st); + void setControlsRect(const QRect &rect); [[nodiscard]] QString text() const; [[nodiscard]] bool shouldBeHidden() const; + [[nodiscard]] const style::TextStyle &textStyle() const; protected: void paintEvent(QPaintEvent *e) override; @@ -42,9 +47,11 @@ private: void init(int height); not_null _st; + std::unique_ptr _textStyle; object_ptr _shadow; QString _text; - QFont _font; + Ui::Text::String _string; + int _controlsRight = 0; }; diff --git a/ui/platform/mac/ui_window_title_mac.mm b/ui/platform/mac/ui_window_title_mac.mm index c660934..4b1100b 100644 --- a/ui/platform/mac/ui_window_title_mac.mm +++ b/ui/platform/mac/ui_window_title_mac.mm @@ -6,8 +6,10 @@ // #include "ui/platform/mac/ui_window_title_mac.h" +#include "ui/platform/ui_platform_window_title.h" #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" +#include "ui/painter.h" #include "ui/ui_utility.h" #include "base/debug_log.h" #include "styles/style_widgets.h" @@ -19,6 +21,19 @@ namespace Ui { namespace Platform { +namespace internal { + +TitleControls::Layout TitleControlsLayout() { + return TitleControls::Layout{ + .left = { + TitleControls::Control::Close, + TitleControls::Control::Minimize, + TitleControls::Control::Maximize, + } + }; +} + +} // namespace internal TitleWidget::TitleWidget(not_null parent, int height) : RpWidget(parent) @@ -27,9 +42,12 @@ TitleWidget::TitleWidget(not_null parent, int height) init(height); } +TitleWidget::~TitleWidget() = default; + void TitleWidget::setText(const QString &text) { if (_text != text) { _text = text; + _string.setText(textStyle(), text); update(); } } @@ -39,10 +57,18 @@ void TitleWidget::setStyle(const style::WindowTitle &st) { update(); } +void TitleWidget::setControlsRect(const QRect &rect) { + _controlsRight = rect.left() * 2 + rect.width(); +} + bool TitleWidget::shouldBeHidden() const { return !_st->height; } +const style::TextStyle &TitleWidget::textStyle() const { + return *_textStyle; +} + QString TitleWidget::text() const { return _text; } @@ -59,42 +85,54 @@ void TitleWidget::init(int height) { setGeometry(0, 0, width, height); }, lifetime()); + const auto setFromFont = [&](const style::font &font) { + _textStyle = std::make_unique(style::TextStyle{ + .font = font, + }); + }; + const auto families = QStringList{ u".AppleSystemUIFont"_q, u".SF NS Text"_q, u"Helvetica Neue"_q, }; for (auto family : families) { - _font.setFamily(family); - if (QFontInfo(_font).family() == _font.family()) { + auto font = QFont(); + font.setFamily(family); + if (QFontInfo(font).family() == font.family()) { static const auto logged = [&] { LOG(("Title Font: %1").arg(family)); return true; }(); + const auto apple = (family == u".AppleSystemUIFont"_q); + setFromFont(style::font( + apple ? 13 : (height * 15) / 24, + apple ? style::internal::FontBold : 0, + family)); break; } } - - if (QFontInfo(_font).family() != _font.family()) { - _font = st::semiboldFont; - _font.setPixelSize(13); - } else if (_font.family() == u".AppleSystemUIFont"_q) { - _font.setBold(true); - _font.setPixelSize(13); - } else { - _font.setPixelSize((height * 15) / 24); + if (!_textStyle) { + setFromFont(style::font(13, style::internal::FontSemibold, 0)); } } void TitleWidget::paintEvent(QPaintEvent *e) { - QPainter p(this); + Painter p(this); const auto active = isActiveWindow(); p.fillRect(rect(), active ? _st->bgActive : _st->bg); - p.setFont(_font); p.setPen(active ? _st->fgActive : _st->fg); - p.drawText(rect(), _text, style::al_center); + + const auto top = (height() - _textStyle->font->height) / 2; + if ((width() - _controlsRight * 2) < _string.maxWidth()) { + const auto left = _controlsRight; + _string.drawElided(p, left, top, width() - left); + } else { + const auto left = (width() - _string.maxWidth()) / 2; + _string.draw(p, left, top, width() - left); + } } void TitleWidget::resizeEvent(QResizeEvent *e) { diff --git a/ui/platform/ui_platform_utility.cpp b/ui/platform/ui_platform_utility.cpp deleted file mode 100644 index 2d07ec5..0000000 --- a/ui/platform/ui_platform_utility.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// This file is part of Desktop App Toolkit, -// a set of libraries for developing nice desktop applications. -// -// For license and copyright information please follow this link: -// https://github.com/desktop-app/legal/blob/master/LEGAL -// -#include "ui/platform/ui_platform_utility.h" - -namespace Ui { -namespace Platform { -namespace { - -rpl::event_stream<> TitleControlsLayoutChanges; - -} // namespace - -rpl::producer<> TitleControlsLayoutChanged() { - return TitleControlsLayoutChanges.events(); -} - -void NotifyTitleControlsLayoutChanged() { - TitleControlsLayoutChanges.fire({}); -} - -} // namespace Platform -} // namespace Ui diff --git a/ui/platform/ui_platform_utility.h b/ui/platform/ui_platform_utility.h index c0bb5ea..c2d304e 100644 --- a/ui/platform/ui_platform_utility.h +++ b/ui/platform/ui_platform_utility.h @@ -6,28 +6,30 @@ // #pragma once -#include "ui/platform/ui_platform_window_title.h" - class QPoint; class QPainter; class QPaintEvent; namespace Ui { -namespace Platform { +class PopupMenu; +} // namespace Ui + +namespace Ui::Platform { [[nodiscard]] bool IsApplicationActive(); -[[nodiscard]] bool TranslucentWindowsSupported(QPoint globalPosition); +[[nodiscard]] bool TranslucentWindowsSupported(); void InitOnTopPanel(not_null panel); void DeInitOnTopPanel(not_null panel); void ReInitOnTopPanel(not_null panel); -void UpdateOverlayed(not_null widget); void ShowOverAll(not_null widget, bool canFocus = true); -void BringToBack(not_null widget); void IgnoreAllActivation(not_null widget); void ClearTransientParent(not_null widget); +void AcceptAllMouseInput(not_null widget); + +void DisableSystemWindowResize(not_null widget, QSize ratio); [[nodiscard]] std::optional IsOverlapped( not_null widget, @@ -36,24 +38,25 @@ void ClearTransientParent(not_null widget); [[nodiscard]] constexpr bool UseMainQueueGeneric(); void DrainMainQueue(); // Needed only if UseMainQueueGeneric() is false. -[[nodiscard]] bool WindowExtentsSupported(); -void SetWindowExtents(QWindow *window, const QMargins &extents); -void UnsetWindowExtents(QWindow *window); -bool ShowWindowMenu(QWindow *window); +[[nodiscard]] bool WindowMarginsSupported(); +void SetWindowMargins(not_null widget, const QMargins &margins); +void UnsetWindowMargins(not_null widget); +void ShowWindowMenu(not_null widget, const QPoint &point); -[[nodiscard]] TitleControls::Layout TitleControlsLayout(); -[[nodiscard]] rpl::producer<> TitleControlsLayoutChanged(); -void NotifyTitleControlsLayoutChanged(); +void FixPopupMenuNativeEmojiPopup(not_null menu); -} // namespace Platform -} // namespace Ui +void SetGeometryWithPossibleScreenChange( + not_null widget, + QRect geometry); + +} // namespace Ui::Platform // Platform dependent implementations. -#ifdef Q_OS_MAC -#include "ui/platform/mac/ui_utility_mac.h" -#elif defined Q_OS_UNIX // Q_OS_MAC -#include "ui/platform/linux/ui_utility_linux.h" -#elif defined Q_OS_WINRT || defined Q_OS_WIN // Q_OS_MAC || Q_OS_UNIX +#if defined Q_OS_WINRT || defined Q_OS_WIN #include "ui/platform/win/ui_utility_win.h" -#endif // Q_OS_MAC || Q_OS_UNIX || Q_OS_WINRT || Q_OS_WIN +#elif defined Q_OS_MAC // Q_OS_WINRT || Q_OS_WIN +#include "ui/platform/mac/ui_utility_mac.h" +#else // Q_OS_WINRT || Q_OS_WIN || Q_OS_MAC +#include "ui/platform/linux/ui_utility_linux.h" +#endif // else for Q_OS_WINRT || Q_OS_WIN || Q_OS_MAC diff --git a/ui/platform/ui_platform_window.cpp b/ui/platform/ui_platform_window.cpp index 09a900e..926f51f 100644 --- a/ui/platform/ui_platform_window.cpp +++ b/ui/platform/ui_platform_window.cpp @@ -13,6 +13,7 @@ #include "ui/painter.h" #include "styles/style_widgets.h" #include "styles/style_layers.h" +#include "styles/palette.h" #include #include @@ -26,6 +27,90 @@ namespace { return st::callShadow; } +[[nodiscard]] int Radius() { + return st::callRadius; +} + +[[nodiscard]] std::array PrepareSides( + const style::Shadow &shadow) { + auto result = std::array(); + const auto extend = shadow.extend; + const auto make = [&]( + int index, + const style::icon &icon, + auto &&postprocess) { + result[index] = icon.instance(st::windowShadowFg->c); + auto p = QPainter(&result[index]); + p.setCompositionMode(QPainter::CompositionMode_Source); + postprocess(p, icon.width(), icon.height()); + }; + make(0, shadow.left, [&](QPainter &p, int width, int height) { + const auto skip = extend.left(); + p.fillRect(skip, 0, width - skip, height, Qt::transparent); + }); + make(1, shadow.top, [&](QPainter &p, int width, int height) { + const auto skip = extend.top(); + p.fillRect(0, skip, width, height - skip, Qt::transparent); + }); + make(2, shadow.right, [&](QPainter &p, int width, int height) { + const auto skip = extend.right(); + p.fillRect(0, 0, width - skip, height, Qt::transparent); + }); + make(3, shadow.bottom, [&](QPainter &p, int width, int height) { + const auto skip = extend.bottom(); + p.fillRect(0, 0, width, height - skip, Qt::transparent); + }); + return result; +} + +[[nodiscard]] std::array PrepareCorners( + const style::Shadow &shadow, + int radius) { + auto result = std::array(); + const auto extend = shadow.extend; + const auto make = [&]( + int index, + const style::icon &icon, + auto &&postprocess) { + result[index] = icon.instance(st::windowShadowFg->c); + auto p = QPainter(&result[index]); + auto hq = PainterHighQualityEnabler(p); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.setBrush(Qt::transparent); + p.setPen(Qt::NoPen); + postprocess(p, icon.width(), icon.height()); + }; + make(0, shadow.topLeft, [&](QPainter &p, int width, int height) { + const auto skipx = extend.left(); + const auto skipy = extend.top(); + width += 2 * radius; + height += 2 * radius; + p.drawRoundedRect(skipx, skipy, width, height, radius, radius); + }); + make(1, shadow.bottomLeft, [&](QPainter &p, int width, int height) { + const auto skipx = extend.left(); + const auto skipy = extend.bottom() + 2 * radius; + width += 2 * radius; + height += 2 * radius; + p.drawRoundedRect(skipx, -skipy, width, height, radius, radius); + }); + make(2, shadow.topRight, [&](QPainter &p, int width, int height) { + const auto skipx = extend.right() + 2 * radius; + const auto skipy = extend.top(); + width += 2 * radius; + height += 2 * radius; + p.drawRoundedRect(-skipx, skipy, width, height, radius, radius); + }); + make(3, shadow.bottomRight, [&](QPainter &p, int width, int height) { + const auto skipx = extend.right() + 2 * radius; + const auto skipy = extend.bottom() + 2 * radius; + width += 2 * radius; + height += 2 * radius; + p.drawRoundedRect(-skipx, -skipy, width, height, radius, radius); + }); + return result; +} + } // namespace BasicWindowHelper::BasicWindowHelper(not_null window) @@ -65,6 +150,14 @@ rpl::producer BasicWindowHelper::systemButtonDown() const { return rpl::never(); } +void BasicWindowHelper::overrideSystemButtonOver(HitTestResult button) { + Expects(button == HitTestResult::None); +} + +void BasicWindowHelper::overrideSystemButtonDown(HitTestResult button) { + Expects(button == HitTestResult::None); +} + void BasicWindowHelper::setTitle(const QString &title) { _window->setWindowTitle(title); } @@ -103,6 +196,10 @@ void BasicWindowHelper::close() { _window->close(); } +int BasicWindowHelper::manualRoundingRadius() const { + return 0; +} + void BasicWindowHelper::setBodyTitleArea( Fn testMethod) { Expects(!_bodyTitleAreaTestMethod || testMethod); @@ -116,6 +213,10 @@ void BasicWindowHelper::setBodyTitleArea( _bodyTitleAreaTestMethod = std::move(testMethod); } +const style::TextStyle &BasicWindowHelper::titleTextStyle() const { + return st::defaultWindowTitle.style; +} + QMargins BasicWindowHelper::nativeFrameMargins() const { const auto inner = window()->geometry(); const auto outer = window()->frameGeometry(); @@ -173,6 +274,10 @@ void BasicWindowHelper::setupBodyTitleAreaEvents() { #endif // Q_OS_WIN _mousePressed = false; _window->windowHandle()->startSystemMove(); + SendSynteticMouseEvent( + body().get(), + QEvent::MouseButtonRelease, + Qt::LeftButton); } } }, body()->lifetime()); @@ -181,44 +286,53 @@ void BasicWindowHelper::setupBodyTitleAreaEvents() { DefaultWindowHelper::DefaultWindowHelper(not_null window) : BasicWindowHelper(window) , _title(Ui::CreateChild(window.get())) -, _body(Ui::CreateChild(window.get())) { +, _body(Ui::CreateChild(window.get())) +, _roundRect(Radius(), st::windowBg) +, _sides(PrepareSides(Shadow())) +, _corners(PrepareCorners(Shadow(), Radius())) { init(); } void DefaultWindowHelper::init() { - _title->show(); - window()->setWindowFlag(Qt::FramelessWindowHint); - - if (WindowExtentsSupported()) { + if (WindowMarginsSupported()) { window()->setAttribute(Qt::WA_TranslucentBackground); } + window()->createWinId(); + _title->show(); + rpl::combine( window()->widthValue(), _windowState.value(), - _title->shownValue() + _title->shownValue(), + TitleControlsLayoutValue() ) | rpl::start_with_next([=]( int width, Qt::WindowStates windowState, - bool shown) { + bool shown, + TitleControls::Layout controlsLayout) { const auto area = resizeArea(); _title->setGeometry( area.left(), area.top(), width - area.left() - area.right(), - _title->st()->height); + _title->controlsGeometry().height() + ? _title->st()->height + : 0); }, _title->lifetime()); rpl::combine( window()->sizeValue(), _windowState.value(), _title->heightValue(), - _title->shownValue() + _title->shownValue(), + TitleControlsLayoutValue() ) | rpl::start_with_next([=]( QSize size, Qt::WindowStates windowState, int titleHeight, - bool titleShown) { + bool titleShown, + TitleControls::Layout controlsLayout) { const auto area = resizeArea(); const auto sizeWithoutMargins = size @@ -230,36 +344,27 @@ void DefaultWindowHelper::init() { area.top() + (titleShown ? titleHeight : 0)); _body->setGeometry(QRect(topLeft, sizeWithoutMargins)); + updateRoundingOverlay(); }, _body->lifetime()); window()->paintRequest( - ) | rpl::start_with_next([=] { - const auto area = resizeArea(); - - if (area.isNull()) { - return; - } - + ) | rpl::filter([=] { + return !hasShadow() && !resizeArea().isNull(); + }) | rpl::start_with_next([=] { Painter p(window()); - - if (hasShadow()) { - Ui::Shadow::paint( - p, - QRect(QPoint(), window()->size()).marginsRemoved(area), - window()->width(), - Shadow()); - } else { - paintBorders(p); - } + paintBorders(p); }, window()->lifetime()); rpl::combine( window()->shownValue(), + _title->shownValue(), _windowState.value() - ) | rpl::start_with_next([=](bool shown, Qt::WindowStates windowState) { - if (shown) { - updateWindowExtents(); - } + ) | rpl::start_with_next([=]( + bool shown, + bool titleShown, + Qt::WindowStates windowState) { + window()->windowHandle()->setFlag(Qt::FramelessWindowHint, titleShown); + updateWindowMargins(); }, window()->lifetime()); window()->events() | rpl::start_with_next([=](not_null e) { @@ -270,6 +375,10 @@ void DefaultWindowHelper::init() { if (mouseEvent->button() == Qt::LeftButton && edges) { window()->windowHandle()->startSystemResize(edges); + SendSynteticMouseEvent( + window().get(), + QEvent::MouseButtonRelease, + Qt::LeftButton); } } else if (e->type() == QEvent::WindowStateChange) { _windowState = window()->windowState(); @@ -279,6 +388,52 @@ void DefaultWindowHelper::init() { QCoreApplication::instance()->installEventFilter(this); } +void DefaultWindowHelper::updateRoundingOverlay() { + if (!hasShadow() || resizeArea().isNull()) { + _roundingOverlay.destroy(); + return; + } else if (_roundingOverlay) { + return; + } + + _roundingOverlay.create(window()); + _roundingOverlay->setAttribute(Qt::WA_TransparentForMouseEvents); + _roundingOverlay->show(); + + window()->sizeValue( + ) | rpl::start_with_next([=](QSize size) { + _roundingOverlay->setGeometry(QRect(QPoint(), size)); + }, _roundingOverlay->lifetime()); + + _roundingOverlay->paintRequest( + ) | rpl::filter([=](QRect clip) { + const auto rect = window()->rect().marginsRemoved(resizeArea()); + const auto radius = Radius(); + const auto radiusWithFix = radius - 1; + const auto radiusSize = QSize(radius, radius); + return clip.intersects(QRect( + rect.topLeft(), + radiusSize + )) || clip.intersects(QRect( + rect.topRight() - QPoint(radiusWithFix, 0), + radiusSize + )) || clip.intersects(QRect( + rect.bottomLeft() - QPoint(0, radiusWithFix), + radiusSize + )) || clip.intersects(QRect( + rect.bottomRight() - QPoint(radiusWithFix, radiusWithFix), + radiusSize + )) || !rect.contains(clip); + }) | rpl::start_with_next([=] { + Painter p(_roundingOverlay); + const auto rect = window()->rect().marginsRemoved(resizeArea()); + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + _roundRect.paint(p, rect, RectPart::AllCorners); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + Shadow::paint(p, rect, window()->width(), Shadow(), _sides, _corners); + }, _roundingOverlay->lifetime()); +} + not_null DefaultWindowHelper::body() { return _body; } @@ -290,14 +445,14 @@ QMargins DefaultWindowHelper::frameMargins() { } bool DefaultWindowHelper::hasShadow() const { - const auto center = window()->geometry().center(); - return WindowExtentsSupported() && TranslucentWindowsSupported(center); + return WindowMarginsSupported() && TranslucentWindowsSupported(); } QMargins DefaultWindowHelper::resizeArea() const { if (window()->isMaximized() || window()->isFullScreen() - || _title->isHidden()) { + || _title->isHidden() + || (!hasShadow() && !_title->controlsGeometry().height())) { return QMargins(); } @@ -375,9 +530,7 @@ void DefaultWindowHelper::setTitleStyle(const style::WindowTitle &st) { } void DefaultWindowHelper::setNativeFrame(bool enabled) { - window()->windowHandle()->setFlag(Qt::FramelessWindowHint, !enabled); _title->setVisible(!enabled); - updateWindowExtents(); } void DefaultWindowHelper::setMinimumSize(QSize size) { @@ -395,6 +548,10 @@ void DefaultWindowHelper::setGeometry(QRect rect) { window()->setGeometry(rect.marginsAdded(bodyPadding())); } +int DefaultWindowHelper::manualRoundingRadius() const { + return _roundingOverlay ? Radius() : 0; +} + void DefaultWindowHelper::paintBorders(QPainter &p) { const auto titleBackground = window()->isActiveWindow() ? _title->st()->bgActive @@ -439,16 +596,13 @@ void DefaultWindowHelper::paintBorders(QPainter &p) { borderColor); } -void DefaultWindowHelper::updateWindowExtents() { +void DefaultWindowHelper::updateWindowMargins() { if (hasShadow() && !_title->isHidden()) { - Platform::SetWindowExtents( - window()->windowHandle(), - resizeArea()); - - _extentsSet = true; - } else if (_extentsSet) { - Platform::UnsetWindowExtents(window()->windowHandle()); - _extentsSet = false; + SetWindowMargins(window(), resizeArea()); + _marginsSet = true; + } else if (_marginsSet) { + UnsetWindowMargins(window()); + _marginsSet = false; } } diff --git a/ui/platform/ui_platform_window.h b/ui/platform/ui_platform_window.h index 230e3d9..6926fa0 100644 --- a/ui/platform/ui_platform_window.h +++ b/ui/platform/ui_platform_window.h @@ -7,9 +7,12 @@ #pragma once #include "base/flags.h" +#include "base/object_ptr.h" +#include "ui/round_rect.h" namespace style { struct WindowTitle; +struct TextStyle; } // namespace style namespace Ui { @@ -46,6 +49,8 @@ public: -> rpl::producer; [[nodiscard]] virtual auto systemButtonDown() const -> rpl::producer; + virtual void overrideSystemButtonOver(HitTestResult button); + virtual void overrideSystemButtonDown(HitTestResult button); virtual void setTitle(const QString &title); virtual void setTitleStyle(const style::WindowTitle &st); virtual void setNativeFrame(bool enabled); @@ -57,8 +62,11 @@ public: virtual void showNormal(); virtual void close(); + virtual int manualRoundingRadius() const; void setBodyTitleArea(Fn testMethod); + [[nodiscard]] virtual const style::TextStyle &titleTextStyle() const; + protected: [[nodiscard]] WindowTitleHitTestFlags bodyTitleAreaHit( QPoint point) const { @@ -89,24 +97,30 @@ public: void setMinimumSize(QSize size) override; void setFixedSize(QSize size) override; void setGeometry(QRect rect) override; + int manualRoundingRadius() const override; protected: bool eventFilter(QObject *obj, QEvent *e) override; private: void init(); + void updateRoundingOverlay(); [[nodiscard]] bool hasShadow() const; [[nodiscard]] QMargins resizeArea() const; [[nodiscard]] Qt::Edges edgesFromPos(const QPoint &pos) const; void paintBorders(QPainter &p); - void updateWindowExtents(); + void updateWindowMargins(); void updateCursor(Qt::Edges edges); [[nodiscard]] int titleHeight() const; [[nodiscard]] QMargins bodyPadding() const; const not_null _title; const not_null _body; - bool _extentsSet = false; + RoundRect _roundRect; + std::array _sides; + std::array _corners; + object_ptr _roundingOverlay = { nullptr }; + bool _marginsSet = false; rpl::variable _windowState = Qt::WindowNoState; }; diff --git a/ui/platform/ui_platform_window_title.cpp b/ui/platform/ui_platform_window_title.cpp index 33a9bf3..04bfac2 100644 --- a/ui/platform/ui_platform_window_title.cpp +++ b/ui/platform/ui_platform_window_title.cpp @@ -65,30 +65,94 @@ void SetupSemiNativeSystemButtons( }, lifetime); } -class TitleControls::Button final : public IconButton { -public: - using IconButton::IconButton; +object_ptr IconTitleButtons::create( + not_null parent, + TitleControl control, + const style::WindowTitle &st) { + const auto make = [&]( + QPointer &my, + const style::IconButton &st) { + Expects(!my); - void setOver(bool over) { - IconButton::setOver(over, StateChangeSource::ByPress); + auto result = object_ptr(parent, st); + my = result.data(); + return result; + }; + switch (control) { + case TitleControl::Minimize: + return make(_minimize, st.minimize); + case TitleControl::Maximize: + return make(_maximizeRestore, st.maximize); + case TitleControl::Close: + return make(_close, st.close); } - void setDown(bool down) { - IconButton::setDown( - down, - StateChangeSource::ByPress, - {}, - Qt::LeftButton); + Unexpected("Control in IconTitleButtons::create."); +} + +void IconTitleButtons::updateState( + bool active, + bool maximized, + const style::WindowTitle &st) { + if (_minimize) { + const auto minimize = active + ? &st.minimizeIconActive + : &st.minimize.icon; + const auto minimizeOver = active + ? &st.minimizeIconActiveOver + : &st.minimize.iconOver; + _minimize->setIconOverride(minimize, minimizeOver); } -}; + if (_maximizeRestore) { + if (maximized) { + const auto restore = active + ? &st.restoreIconActive + : &st.restoreIcon; + const auto restoreOver = active + ? &st.restoreIconActiveOver + : &st.restoreIconOver; + _maximizeRestore->setIconOverride(restore, restoreOver); + } else { + const auto maximize = active + ? &st.maximizeIconActive + : &st.maximize.icon; + const auto maximizeOver = active + ? &st.maximizeIconActiveOver + : &st.maximize.iconOver; + _maximizeRestore->setIconOverride(maximize, maximizeOver); + } + } + if (_close) { + const auto close = active + ? &st.closeIconActive + : &st.close.icon; + const auto closeOver = active + ? &st.closeIconActiveOver + : &st.close.iconOver; + _close->setIconOverride(close, closeOver); + } +} TitleControls::TitleControls( not_null parent, const style::WindowTitle &st, Fn maximize) +: TitleControls( + parent, + st, + std::make_unique(), + std::move(maximize)) { +} + +TitleControls::TitleControls( + not_null parent, + const style::WindowTitle &st, + std::unique_ptr buttons, + Fn maximize) : _st(&st) -, _minimize(parent, _st->minimize) -, _maximizeRestore(parent, _st->maximize) -, _close(parent, _st->close) +, _buttons(std::move(buttons)) +, _minimize(_buttons->create(parent, Control::Minimize, st)) +, _maximizeRestore(_buttons->create(parent, Control::Maximize, st)) +, _close(_buttons->create(parent, Control::Close, st)) , _maximizedState(parent->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) , _activeState(parent->isActiveWindow()) { @@ -167,12 +231,9 @@ void TitleControls::init(Fn maximize) { }); _close->setPointerCursor(false); - parent()->widthValue( - ) | rpl::start_with_next([=](int width) { - updateControlsPosition(); - }, _close->lifetime()); - - TitleControlsLayoutChanged( + rpl::combine( + parent()->widthValue(), + TitleControlsLayoutValue() ) | rpl::start_with_next([=] { updateControlsPosition(); }, _close->lifetime()); @@ -218,11 +279,18 @@ void TitleControls::raise() { _close->raise(); } -HitTestResult TitleControls::hitTest(QPoint point) const { - const auto test = [&](const object_ptr