From 28a81f2dd8c247a0ce7d768c33ff4a834936da9f Mon Sep 17 00:00:00 2001 From: Volodymyr Kozieiev Date: Mon, 6 Jan 2025 12:03:36 +0000 Subject: [PATCH 01/15] =?UTF-8?q?=F0=9F=8E=84=20=F0=9F=A7=B9=20=20New=20Ye?= =?UTF-8?q?ar=20cleanup=20(#21868)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * big cleannup: warnings fixed, unused code removed --- .carve_ignore | 185 ------------ .clj-kondo/config.edn | 31 +- src/legacy/status_im/browser/core.cljs | 62 +--- src/legacy/status_im/browser/core_test.cljs | 120 -------- src/legacy/status_im/browser/permissions.cljs | 16 +- .../status_im/browser/permissions_test.cljs | 90 ------ .../status_im/chat/models/mentions.cljs | 2 +- src/legacy/status_im/chat/models/message.cljs | 4 +- src/legacy/status_im/communities/core.cljs | 6 +- .../status_im/data_store/communities.cljs | 6 - src/legacy/status_im/data_store/messages.cljs | 12 +- .../status_im/data_store/pin_messages.cljs | 2 +- src/legacy/status_im/ens/core.cljs | 15 +- src/legacy/status_im/ethereum/macros.clj | 24 +- src/legacy/status_im/ethereum/tokens.cljs | 51 +--- .../status_im/ethereum/transactions/core.cljs | 87 ++---- src/legacy/status_im/events.cljs | 20 +- src/legacy/status_im/fleet/core.cljs | 2 +- src/legacy/status_im/group_chats/core.cljs | 21 +- src/legacy/status_im/group_chats/db.cljs | 26 -- src/legacy/status_im/log_level/core.cljs | 2 +- .../status_im/mailserver/constants.cljs | 18 -- .../status_im/multiaccounts/create/core.cljs | 6 - .../status_im/multiaccounts/recover/core.cljs | 31 -- .../multiaccounts/reset_password/core.cljs | 94 ------ .../status_im/multiaccounts/update/core.cljs | 47 ++- src/legacy/status_im/node/core.cljs | 9 +- src/legacy/status_im/pairing/core.cljs | 4 +- src/legacy/status_im/profile/core.cljs | 2 +- src/legacy/status_im/qr_scanner/core.cljs | 4 +- .../status_im/react_native/resources.cljs | 8 +- src/legacy/status_im/stickers/core.cljs | 16 -- src/legacy/status_im/subs/ens.cljs | 94 +----- src/legacy/status_im/subs/mailservers.cljs | 42 --- src/legacy/status_im/subs/root.cljs | 1 - src/legacy/status_im/subs/stickers.cljs | 22 -- .../status_im/ui/components/accordion.cljs | 56 ---- .../status_im/ui/components/action_sheet.cljs | 2 +- .../ui/components/animated_header.cljs | 69 ----- .../status_im/ui/components/animation.cljs | 58 ---- .../ui/components/bottom_panel/views.cljs | 152 ---------- .../status_im/ui/components/button/view.cljs | 1 - .../ui/components/chat_icon/screen.cljs | 89 +----- .../ui/components/chat_icon/styles.cljs | 140 +-------- .../ui/components/checkbox/styles.cljs | 15 - .../ui/components/checkbox/view.cljs | 27 -- .../status_im/ui/components/colors.cljs | 36 +-- .../ui/components/common/common.cljs | 20 +- .../ui/components/common/styles.cljs | 23 -- .../ui/components/copyable_text.cljs | 129 --------- src/legacy/status_im/ui/components/core.cljs | 5 - .../emoji_thumbnail/color_picker.cljs | 52 ---- .../components/emoji_thumbnail/preview.cljs | 19 -- .../ui/components/emoji_thumbnail/styles.cljs | 171 ----------- .../ui/components/emoji_thumbnail/utils.cljs | 16 -- .../status_im/ui/components/invite/views.cljs | 30 -- .../keyboard_avoid_presentation.cljs | 17 -- .../status_im/ui/components/list/footer.cljs | 18 -- .../status_im/ui/components/list/styles.cljs | 41 --- .../ui/components/profile_header/view.cljs | 110 -------- src/legacy/status_im/ui/components/react.cljs | 125 +------- .../ui/components/search_input/view.cljs | 45 --- .../status_im/ui/components/slider.cljs | 10 - src/legacy/status_im/ui/components/tabs.cljs | 36 --- .../status_im/ui/components/text_input.cljs | 2 - .../ui/components/toastable_highlight.cljs | 121 -------- .../ui/components/tooltip/styles.cljs | 31 -- .../ui/components/tooltip/views.cljs | 22 -- .../ui/screens/advanced_settings/views.cljs | 5 - .../ui/screens/browser/bookmarks/views.cljs | 55 ---- .../ui/screens/browser/eip3085/sheet.cljs | 57 ---- .../ui/screens/browser/eip3326/sheet.cljs | 68 ----- .../ui/screens/browser/empty_tab/styles.cljs | 26 -- .../ui/screens/browser/empty_tab/views.cljs | 30 -- .../ui/screens/browser/options/views.cljs | 23 -- .../ui/screens/chat/message/legacy_style.cljs | 54 ---- .../ui/screens/chat/message/legacy_view.cljs | 57 ---- .../status_im/ui/screens/chat/utils.cljs | 30 -- .../ui/screens/communities/invite.cljs | 104 ------- .../ui/screens/fleet_settings/styles.cljs | 3 - .../ui/screens/log_level_settings/styles.cljs | 3 - .../notifications_settings/events.cljs | 6 +- .../edit_mailserver/styles.cljs | 38 --- .../edit_mailserver/views.cljs | 90 ------ .../offline_messaging_settings/styles.cljs | 11 - .../status_im/ui/screens/pairing/styles.cljs | 6 - .../ui/screens/profile/components/sheets.cljs | 32 --- .../ui/screens/profile/components/styles.cljs | 42 +-- .../ui/screens/profile/components/views.cljs | 39 +-- .../ui/screens/profile/seed/styles.cljs | 10 - .../ui/screens/profile/user/edit_picture.cljs | 62 ---- .../ui/screens/profile/user/styles.cljs | 6 - .../profile/visibility_status/styles.cljs | 78 ----- .../profile/visibility_status/utils.cljs | 20 -- .../profile/visibility_status/views.cljs | 239 ---------------- .../ui/screens/reset_password/views.cljs | 80 +----- src/legacy/status_im/ui/screens/screens.cljs | 13 - .../ui/screens/wakuv2_settings/styles.cljs | 4 - src/legacy/status_im/utils/async.cljs | 25 -- src/legacy/status_im/utils/build.clj | 20 -- src/legacy/status_im/utils/core.cljc | 15 - .../status_im/utils/deprecated_types.cljs | 23 -- src/legacy/status_im/utils/dimensions.cljs | 9 +- src/legacy/status_im/utils/image.cljs | 9 - src/legacy/status_im/utils/label.cljs | 25 -- src/legacy/status_im/utils/logging/core.cljs | 10 +- src/legacy/status_im/utils/mobile_sync.cljs | 4 - src/legacy/status_im/utils/name.cljs | 33 --- src/legacy/status_im/utils/priority_map.cljs | 267 ------------------ .../status_im/utils/transducers_test.cljs | 14 - src/legacy/status_im/utils/utils.cljs | 34 --- src/legacy/status_im/utils/utils_test.cljs | 27 +- .../visibility_status_updates/core.cljs | 12 +- src/legacy/status_im/waku/core.cljs | 6 +- src/native_module/push_notifications.cljs | 4 - src/quo/components/colors/color/view.cljs | 1 + .../common/not_implemented/style.cljs | 13 - .../common/not_implemented/view.cljs | 11 - .../community/community_list_view.cljs | 43 --- src/quo/components/community/style.cljs | 8 - src/quo/components/counter/step/style.cljs | 1 + .../dividers/strength_divider/view.cljs | 1 + .../components/drawers/drawer_top/style.cljs | 4 - .../dropdowns/dropdown_input/style.cljs | 7 - .../components/graph/wallet_graph/style.cljs | 10 +- src/quo/components/header.cljs | 208 -------------- .../components/list_items/account/style.cljs | 7 - .../list_items/missing_keypair/style.cljs | 10 - src/quo/components/loaders/skeleton.cljs | 93 ------ src/quo/components/markdown/list/style.cljs | 3 - src/quo/components/messages/gap.cljs | 1 - .../selectors/reaction_resource.clj | 31 -- .../selectors/reaction_resource.cljs | 12 +- .../components/settings/category/style.cljs | 16 -- .../settings/reorder_item/style.cljs | 3 - .../components/tags/context_tag/style.cljs | 5 - .../components/wallet/token_input/style.cljs | 4 - src/quo/core.cljs | 11 - src/react_native/audio_toolkit.cljs | 30 -- src/react_native/background_timer.cljs | 8 - src/react_native/core.cljs | 24 -- src/react_native/gesture.cljs | 4 - src/react_native/navigation.cljs | 23 +- src/react_native/permissions.cljs | 5 +- src/react_native/reanimated.cljs | 15 +- src/react_native/svg.cljs | 2 - src/react_native/wallet_connect.cljs | 4 - src/status_im/common/alert_banner/style.cljs | 4 - src/status_im/common/bottom_sheet/style.cljs | 6 - src/status_im/common/home/actions/view.cljs | 10 - src/status_im/common/keychain/events.cljs | 1 - .../common/lightbox/text_sheet/style.cljs | 7 - .../lightbox/zoomable_image/constants.cljs | 2 - .../common/new_device_sheet/style.cljs | 16 +- src/status_im/common/pairing/events.cljs | 4 +- .../password_authentication/events.cljs | 13 - .../common/password_authentication/view.cljs | 42 --- src/status_im/common/router.cljs | 14 - src/status_im/common/router_test.cljs | 1 - src/status_im/common/scan_qr_code/style.cljs | 4 - src/status_im/common/scroll_page/style.cljs | 26 -- src/status_im/common/signals/events.cljs | 3 +- .../enter_password/style.cljs | 5 - src/status_im/common/timer/events.cljs | 18 -- src/status_im/common/universal_links.cljs | 6 - src/status_im/config.cljs | 28 +- src/status_im/constants.cljs | 134 +-------- .../contexts/centralized_metrics/events.cljs | 2 + src/status_im/contexts/chat/events.cljs | 9 +- src/status_im/contexts/chat/events_test.cljs | 9 - .../contexts/chat/group/common/style.cljs | 7 - .../contexts/chat/group/details/style.cljs | 14 - .../chat/home/add_new_contact/style.cljs | 4 +- src/status_im/contexts/chat/home/style.cljs | 26 -- .../chat/messenger/composer/constants.cljs | 13 +- .../chat/messenger/composer/events.cljs | 47 +-- .../messenger/composer/gradients/style.cljs | 42 --- .../messenger/composer/gradients/view.cljs | 30 -- .../chat/messenger/composer/handlers.cljs | 24 -- .../composer/link_preview/events.cljs | 2 +- .../messenger/composer/mentions/style.cljs | 12 - .../chat/messenger/composer/selection.cljs | 25 -- .../chat/messenger/composer/style.cljs | 34 +-- .../chat/messenger/composer/utils.cljs | 36 --- .../chat/messenger/messages/constants.cljs | 1 - .../messages/content/audio/style.cljs | 4 - .../messenger/messages/content/pin/style.cljs | 28 -- .../messages/delete_message/events.cljs | 2 +- .../delete_message_for_me/events.cljs | 2 +- .../chat/messenger/messages/drawers/view.cljs | 7 - .../messenger/messages/list/events_test.cljs | 17 -- .../chat/messenger/messages/list/view.cljs | 59 ---- .../chat/messenger/messages/pin/events.cljs | 2 +- .../messenger/messages/transport/events.cljs | 6 +- .../chat/messenger/photo_selector/events.cljs | 4 +- .../chat/messenger/photo_selector/style.cljs | 31 -- .../accounts_selection/events_test.cljs | 14 - .../share_community_channel/style.cljs | 15 - .../contexts/communities/events.cljs | 2 +- .../contexts/communities/home/style.cljs | 64 ----- .../contexts/communities/overview/utils.cljs | 22 -- .../onboarding/create_password/style.cljs | 3 - .../onboarding/share_usage/style.cljs | 5 - .../contexts/onboarding/sign_in/style.cljs | 95 ------- .../contexts/preview/quo/preview.clj | 10 - .../contexts/preview/quo/preview.cljs | 3 +- .../preview/quo/tabs/account_selector.cljs | 27 -- .../profile/push_notifications/events.cljs | 5 +- .../profile/settings/header/style.cljs | 14 +- .../password/change_password/style.cljs | 3 - .../settings/screens/password/style.cljs | 9 - .../wallet/network_settings/style.cljs | 6 +- .../shell/activity_center/events.cljs | 17 +- .../shell/activity_center/events_test.cljs | 44 --- .../notification/common/style.cljs | 3 - .../notification/mentions/style.cljs | 3 - .../notification/reply/style.cljs | 3 - .../contexts/shell/activity_center/style.cljs | 18 -- .../contexts/shell/share/events.cljs | 2 +- src/status_im/contexts/shell/share/style.cljs | 27 +- .../syncing/enter_sync_code/style.cljs | 5 - src/status_im/contexts/syncing/events.cljs | 6 +- .../contexts/syncing/setup_syncing/style.cljs | 3 - .../syncing/syncing_devices_list/style.cljs | 6 - src/status_im/contexts/syncing/utils.cljs | 10 +- .../contexts/wallet/account/style.cljs | 4 - .../new_keypair/confirm_backup/style.cljs | 4 - .../add_account/create_account/style.cljs | 4 - .../wallet/bridge/select_asset/style.cljs | 4 - .../wallet/common/activity_tab/constants.cljs | 43 --- .../create_or_edit_account/style.cljs | 15 +- .../contexts/wallet/common/utils.cljs | 129 --------- .../wallet/common/utils/networks.cljs | 13 - src/status_im/contexts/wallet/item_types.cljs | 8 - .../wallet/send/input_amount/style.cljs | 24 +- .../wallet/send/select_address/style.cljs | 8 - .../wallet/send/select_asset/style.cljs | 10 - .../send/transaction_settings/style.cljs | 14 - .../wallet/sheets/account_options/style.cljs | 6 - .../unpreferred_networks_alert/style.cljs | 10 - .../unpreferred_networks_alert/view.cljs | 28 -- src/status_im/contexts/wallet/swap/utils.cljs | 13 - src/status_im/core.cljs | 2 + src/status_im/events.cljs | 1 - src/status_im/feature_flags.cljs | 6 - src/status_im/navigation/events.cljs | 6 +- src/status_im/setup/hot_reload.cljs | 6 + src/status_im/subs/chats.cljs | 54 +--- src/status_im/subs/communities.cljs | 14 - src/status_im/subs/general.cljs | 18 -- src/status_im/subs/profile.cljs | 83 ------ src/status_im/subs/wallet/buy.cljs | 10 - src/status_im/subs/wallet/collectibles.cljs | 9 - .../subs/wallet/collectibles_test.cljs | 26 -- .../subs/wallet/dapps/proposals_test.cljs | 35 --- src/status_im/subs/wallet/send.cljs | 15 - src/status_im/subs/wallet/wallet.cljs | 17 -- src/status_im/subs/wallet/wallet_test.cljs | 52 ---- src/test_helpers/component.cljs | 57 ---- src/test_helpers/integration.cljs | 39 --- src/test_helpers/matchers.cljs | 4 + src/test_helpers/unit.clj | 2 +- src/test_helpers/unit.cljs | 79 +----- src/tests/contract_test/wallet_test.cljs | 23 -- src/tests/integration_test/constants.cljs | 2 - src/utils/address.cljs | 11 - src/utils/collection.cljs | 5 - src/utils/collection_test.cljs | 12 + src/utils/datetime.cljs | 36 --- src/utils/datetime_test.cljs | 2 - src/utils/ens/core.cljs | 9 - src/utils/ethereum/chain.cljs | 17 -- src/utils/ethereum/eip/eip681_test.cljs | 13 - src/utils/i18n.cljs | 5 +- src/utils/i18n_goog.cljs | 76 ----- src/utils/money.cljs | 79 ------ src/utils/network/core.cljs | 5 - src/utils/number.cljs | 3 +- src/utils/re_frame.clj | 1 - src/utils/re_frame_test.cljs | 6 +- src/utils/string.cljs | 19 -- src/utils/transforms.cljs | 7 - src/utils/worklets/bottom_sheet.cljs | 11 - .../worklets/identifiers_highlighting.cljs | 31 -- src/utils/worklets/scroll_view.cljs | 7 - 285 files changed, 255 insertions(+), 7600 deletions(-) delete mode 100644 .carve_ignore delete mode 100644 src/legacy/status_im/browser/core_test.cljs delete mode 100644 src/legacy/status_im/browser/permissions_test.cljs delete mode 100644 src/legacy/status_im/group_chats/db.cljs delete mode 100644 src/legacy/status_im/mailserver/constants.cljs delete mode 100644 src/legacy/status_im/multiaccounts/recover/core.cljs delete mode 100644 src/legacy/status_im/multiaccounts/reset_password/core.cljs delete mode 100644 src/legacy/status_im/subs/stickers.cljs delete mode 100644 src/legacy/status_im/ui/components/accordion.cljs delete mode 100644 src/legacy/status_im/ui/components/animated_header.cljs delete mode 100644 src/legacy/status_im/ui/components/bottom_panel/views.cljs delete mode 100644 src/legacy/status_im/ui/components/checkbox/styles.cljs delete mode 100644 src/legacy/status_im/ui/components/checkbox/view.cljs delete mode 100644 src/legacy/status_im/ui/components/copyable_text.cljs delete mode 100644 src/legacy/status_im/ui/components/emoji_thumbnail/color_picker.cljs delete mode 100644 src/legacy/status_im/ui/components/emoji_thumbnail/preview.cljs delete mode 100644 src/legacy/status_im/ui/components/emoji_thumbnail/styles.cljs delete mode 100644 src/legacy/status_im/ui/components/emoji_thumbnail/utils.cljs delete mode 100644 src/legacy/status_im/ui/components/invite/views.cljs delete mode 100644 src/legacy/status_im/ui/components/keyboard_avoid_presentation.cljs delete mode 100644 src/legacy/status_im/ui/components/list/footer.cljs delete mode 100644 src/legacy/status_im/ui/components/profile_header/view.cljs delete mode 100644 src/legacy/status_im/ui/components/search_input/view.cljs delete mode 100644 src/legacy/status_im/ui/components/slider.cljs delete mode 100644 src/legacy/status_im/ui/components/tabs.cljs delete mode 100644 src/legacy/status_im/ui/components/toastable_highlight.cljs delete mode 100644 src/legacy/status_im/ui/screens/browser/bookmarks/views.cljs delete mode 100644 src/legacy/status_im/ui/screens/browser/eip3085/sheet.cljs delete mode 100644 src/legacy/status_im/ui/screens/browser/eip3326/sheet.cljs delete mode 100644 src/legacy/status_im/ui/screens/chat/utils.cljs delete mode 100644 src/legacy/status_im/ui/screens/communities/invite.cljs delete mode 100644 src/legacy/status_im/ui/screens/offline_messaging_settings/edit_mailserver/styles.cljs delete mode 100644 src/legacy/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs delete mode 100644 src/legacy/status_im/ui/screens/profile/components/sheets.cljs delete mode 100644 src/legacy/status_im/ui/screens/profile/user/edit_picture.cljs delete mode 100644 src/legacy/status_im/ui/screens/profile/user/styles.cljs delete mode 100644 src/legacy/status_im/ui/screens/profile/visibility_status/views.cljs delete mode 100644 src/legacy/status_im/utils/image.cljs delete mode 100644 src/legacy/status_im/utils/label.cljs delete mode 100644 src/legacy/status_im/utils/name.cljs delete mode 100644 src/legacy/status_im/utils/priority_map.cljs delete mode 100644 src/quo/components/common/not_implemented/style.cljs delete mode 100644 src/quo/components/common/not_implemented/view.cljs delete mode 100644 src/quo/components/header.cljs delete mode 100644 src/quo/components/loaders/skeleton.cljs delete mode 100644 src/quo/components/selectors/reaction_resource.clj delete mode 100644 src/status_im/common/password_authentication/events.cljs delete mode 100644 src/status_im/common/password_authentication/view.cljs delete mode 100644 src/status_im/common/timer/events.cljs delete mode 100644 src/status_im/contexts/chat/home/style.cljs delete mode 100644 src/status_im/contexts/chat/messenger/composer/gradients/style.cljs delete mode 100644 src/status_im/contexts/chat/messenger/composer/gradients/view.cljs delete mode 100644 src/status_im/contexts/communities/home/style.cljs delete mode 100644 src/status_im/contexts/communities/overview/utils.cljs delete mode 100644 src/status_im/contexts/onboarding/sign_in/style.cljs delete mode 100644 src/status_im/contexts/preview/quo/preview.clj delete mode 100644 src/status_im/contexts/wallet/send/transaction_settings/style.cljs delete mode 100644 src/status_im/contexts/wallet/sheets/unpreferred_networks_alert/style.cljs delete mode 100644 src/status_im/contexts/wallet/sheets/unpreferred_networks_alert/view.cljs delete mode 100644 src/status_im/subs/wallet/collectibles_test.cljs create mode 100644 src/utils/collection_test.cljs delete mode 100644 src/utils/worklets/bottom_sheet.cljs delete mode 100644 src/utils/worklets/identifiers_highlighting.cljs delete mode 100644 src/utils/worklets/scroll_view.cljs diff --git a/.carve_ignore b/.carve_ignore deleted file mode 100644 index 4c31c0d303d5..000000000000 --- a/.carve_ignore +++ /dev/null @@ -1,185 +0,0 @@ -legacy.status-im.utils.build/warning-handler -legacy.status-im.utils.build/get-current-sha -status-im.constants/spacing-char -status-im.constants/arg-wrapping-char -legacy.status-im.ios.core/init -legacy.status-im.ui.components.camera/aspects -legacy.status-im.ui.components.camera/capture-targets -legacy.status-im.ui.components.camera/set-torch -legacy.status-im.ui.components.camera/request-access-ios -legacy.status-im.chat.models.message-content/stylings -legacy.status-im.chat.models.message-content/actions -legacy.status-im.chat.models.message-content/blank-string -legacy.status-im.chat.models.message-content/sorted-ranges -legacy.status-im.ethereum.mnemonic/words->passphrase -native-module.core/listener -native-module.core/multiaccount-reset -native-module.core/extract-group-membership-signatures -native-module.core/sign-group-membership -native-module.core/update-mailservers -legacy.status-im.ethereum.abi-spec/bytes-to-hex -legacy.status-im.android.core/init -legacy.status-im.chat.models.message/transport-keys -legacy.status-im.utils.datetime/week -legacy.status-im.utils.datetime/time-ago -legacy.status-im.utils.datetime/format-date -legacy.status-im.utils.datetime/get-ordinal-date -reagent.dom/render -reagent.dom/unmount-component-at-node -reagent.dom/dom-node -reagent.dom/force-update-all -legacy.status-im.multiaccounts.create.core/get-new-key-code -legacy.status-im.ethereum.decode/string -legacy.status-im.ui.screens.network.views/mainnet? -legacy.status-im.data-store.chats/event->string -legacy.status-im.mailserver.constants/seven-days -legacy.status-im.mailserver.constants/connection-timeout -legacy.status-im.hardwallet.card/install-applet -legacy.status-im.hardwallet.card/install-cash-applet -legacy.status-im.multiaccount.login.data-test/all-contacts -legacy.status-im.multiaccount.login.data-test/multiaccounts -legacy.status-im.multiaccount.login.data-test/get-chats -legacy.status-im.multiaccount.login.data-test/transport -legacy.status-im.multiaccount.login.data-test/topics -legacy.status-im.utils.utils/clear-timeout -legacy.status-im.utils.handlers/logged-in -legacy.status-im.multiaccounts.model/credentials -legacy.status-im.multiaccounts.login.core/contract-fleet? -legacy.status-im.multiaccounts.login.core/fetch-nodes -status-im.config/rpc-networks-only? -status-im.config/waku-enabled? -legacy.status-im.utils.pairing/has-paired-installations? -legacy.status-im.tribute-to-talk.core-test/user-cofx -mocks.js-dependencies/action-button -mocks.js-dependencies/camera -mocks.js-dependencies/dismiss-keyboard -mocks.js-dependencies/emoji-picker -mocks.js-dependencies/i18n -mocks.js-dependencies/qr-code -mocks.js-dependencies/svg -mocks.js-dependencies/icons -mocks.js-dependencies/webview -mocks.js-dependencies/desktop-linking -mocks.js-dependencies/desktop-shortcuts -mocks.js-dependencies/snoopy -mocks.js-dependencies/snoopy-filter -mocks.js-dependencies/snoopy-bars -mocks.js-dependencies/snoopy-buffer -mocks.js-dependencies/desktop-menu -mocks.js-dependencies/desktop-config -mocks.js-dependencies/react-native-navigation-twopane -mocks.js-dependencies/react-native-screens -mocks.js-dependencies/react-native-shake -mocks.js-dependencies/back-handler -mocks.js-dependencies/react -mocks.js-dependencies/react-navigation-native -mocks.js-dependencies/react-navigation-stack -mocks.js-dependencies/react-navigation-bottom-tabs -mocks.js-dependencies/react-native-haptic-feedback -mocks.js-dependencies/mock -quo.previews.main/init -legacy.status-im.chat.models.message-list-test/descending-range -legacy.status-im.chat.models.message-list-test/random-range -legacy.status-im.ethereum.eip165/supports? -legacy.status-im.utils.hex/valid-hex? -legacy.status-im.multiaccounts.core/chat-send? -legacy.status-im.hardwallet.simulated-keycard/install-cash-applet -legacy.status-im.hardwallet.simulated-keycard/sign-typed-data -legacy.status-im.utils.core/safe-read-message-content -legacy.status-im.ui.components.react/native-modules -legacy.status-im.ui.components.react/progress-bar -react-native.fs/move-file -react-native.fs/read-dir -react-native.fs/mkdir -react-native.fs/unlink -react-native.fs/file-exists? -legacy.status-im.ui.components.colors/white -legacy.status-im.ui.components.colors/black -legacy.status-im.ui.components.core/animated-header -legacy.status-im.ui.components.core/safe-area-provider -legacy.status-im.ui.components.core/safe-area-consumer -legacy.status-im.ui.components.core/safe-area-view -legacy.status-im.utils.universal-links.core/open! -legacy.status-im.transport.filters.core-test/member-2 -legacy.status-im.ui.screens.chat.ttt/one-to-one-chat-description-container -legacy.status-im.ethereum.ens/ttl -legacy.status-im.ethereum.ens/addr-hash -legacy.status-im.ethereum.ens/name-hash -legacy.status-im.ethereum.ens/ABI-hash -legacy.status-im.ethereum.ens/pubkey-hash -legacy.status-im.network.core/get-network -status-im.constants/desktop-content-types -status-im.constants/blocks-per-hour -status-im.constants/one-earth-day -status-im.constants/left-pane-min-width -status-im.constants/system -status-im.constants/contact-discovery -status-im.constants/send-transaction-failed-parse-response -status-im.constants/send-transaction-failed-parse-params -status-im.constants/send-transaction-no-account-selected -status-im.constants/send-transaction-invalid-tx-sender -status-im.constants/web3-get-logs -status-im.constants/web3-transaction-receipt -status-im.constants/web3-new-filter -status-im.constants/web3-new-pending-transaction-filter -status-im.constants/web3-new-block-filter -status-im.constants/web3-uninstall-filter -status-im.constants/web3-get-filter-changes -status-im.constants/web3-shh-post -status-im.constants/web3-shh-new-identity -status-im.constants/web3-shh-has-identity -status-im.constants/web3-shh-new-group -status-im.constants/web3-shh-add-to-group -status-im.constants/web3-shh-new-filter -status-im.constants/web3-shh-uninstall-filter -status-im.constants/web3-shh-get-filter-changes -status-im.constants/web3-shh-get-messages -status-im.constants/status-create-address -status-im.constants/event-transfer-hash -status-im.constants/regx-rtl-characters -status-im.constants/desktop-msg-chars-hard-limit -status-im.constants/debug-metrics -status-im.constants/scan-qr-code -status-im.constants/ipfs-proto-code -status-im.constants/swarm-proto-code -legacy.status-im.multiaccounts.update.publisher/publish-update! -legacy.status-im.utils.async/task-queue -legacy.status-im.utils.async/async-periodic-run! -legacy.status-im.desktop.core/app-root -legacy.status-im.desktop.core/init -legacy.status-im.chat.models-test/test-db -legacy.status-im.ui.components.spacing/padding-vertical -legacy.status-im.utils.money/percent-change -utils.debounce/clear-all -legacy.status-im.transport.db/create-chat -legacy.status-im.utils.priority-map/priority-map -legacy.status-im.utils.priority-map/priority-map-by -legacy.status-im.utils.priority-map/priority-map-keyfn -legacy.status-im.utils.priority-map/empty-message-map -legacy.status-im.wallet.choose-recipient.core/use-default-eth-gas -legacy.status-im.ui.components.animation/decay -legacy.status-im.ui.components.animation/remove-all-listeners -legacy.status-im.ui.components.animation/stop-animation -legacy.status-im.ui.components.animation/animated -legacy.status-im.ui.components.animation/add -legacy.status-im.ui.components.animation/subtract -legacy.status-im.ui.components.animation/get-layout -legacy.status-im.wallet.transactions-test/uri-query-data -legacy.status-im.utils.name/shortened-name -legacy.status-im.ui.components.button.haptic/trigger -legacy.status-im.contact.db/filter-dapps -legacy.status-im.contact.db/filter-group-contacts -legacy.status-im.contact.db/legacy-pending? -legacy.status-im.utils.transducers-test/preview-call-1 -legacy.status-im.utils.transducers-test/preview-call-2 -legacy.status-im.utils.types/to-string -legacy.status-im.chat.db/datemark? -legacy.status-im.chat.db/gap? -legacy.status-im.chat.db/map->sorted-seq -legacy.status-im.utils.snoopy/status-module-filter -legacy.status-im.utils.snoopy/websocket-filter -legacy.status-im.utils.snoopy/touches-filter -legacy.status-im.utils.snoopy/native-animation-filter -legacy.status-im.utils.snoopy/keyboard-observer-filter -legacy.status-im.utils.multihash/hex -legacy.status-im.utils.multihash/decode-array diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn index d34a725d03eb..c653dc1048d8 100644 --- a/.clj-kondo/config.edn +++ b/.clj-kondo/config.edn @@ -4,7 +4,7 @@ legacy.status-im.utils.views/letsubs clojure.core/let reagent.core/with-let clojure.core/let legacy.status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all - utils.re-frame/defn clj-kondo.lint-as/def-catch-all + utils.re-frame/defn clojure.core/defn quo.react/with-deps-check clojure.core/fn quo.previews.preview/list-comp clojure.core/for legacy.status-im.utils.styles/def clojure.core/def @@ -13,7 +13,29 @@ test-helpers.unit/deftest-event clojure.core/defn taoensso.tufte/defnp clojure.core/defn} - :linters {:case-duplicate-test {:level :error} + :linters {:clojure-lsp/unused-public-var {:exclude-when-defined-by #{utils.re-frame/defn} + :exclude #{ + ;; even if we are not + ;; using color now, we + ;; will need it later + quo.foundations.colors + + ;; same for funcs from + ;; native-module + native-module.core + + ;; some funcs used + ;; temporarily during + ;; development + test-helpers.component + test-helpers.unit + + ;; not sure if unused + ;; functions here should + ;; be removed: + keycard.keycard + react-native.fs}} + :case-duplicate-test {:level :error} :case-quoted-test {:level :error} :case-symbol-test {:level :error} :clj-kondo-config {:level :error} @@ -40,7 +62,8 @@ :equals-true {:level :error} :inline-def {:level :error} :invalid-arity {:skip-args [legacy.status-im.utils.fx/defn - utils.re-frame/defn]} + utils.re-frame/defn + utils.re-frame/merge]} :loop-without-recur {:level :error} :minus-one {:level :error} :misplaced-docstring {:level :error} @@ -53,6 +76,8 @@ :redundant-do {:level :error} :redundant-let {:level :error} :refer-all {:level :error} + ;; ignore error in config itself saying that `:shadowed-fn-param` is unknown + #_{:clj-kondo/ignore [:clj-kondo-config]} :shadowed-fn-param {:level :error} :shadowed-var {:level :error ;; We temporarily use :include to define an diff --git a/src/legacy/status_im/browser/core.cljs b/src/legacy/status_im/browser/core.cljs index 76ccb9bf4e23..9854608dfd25 100644 --- a/src/legacy/status_im/browser/core.cljs +++ b/src/legacy/status_im/browser/core.cljs @@ -19,8 +19,6 @@ [status-im.constants :as constants] [status-im.contexts.chat.events :as chat.events] [status-im.navigation.events :as navigation] - [taoensso.timbre :as log] - [utils.address :as address] [utils.debounce :as debounce] [utils.ens.core :as utils.ens] [utils.ethereum.chain :as chain] @@ -139,13 +137,11 @@ {:events [:browser/delete-bookmark]} [{:keys [db] :as cofx} url] - (let [old-bookmark (get-in db [:bookmarks/bookmarks url]) - removed-bookmark (merge old-bookmark {:removed true})] - (rf/merge cofx - {:db (update db :bookmarks/bookmarks dissoc url) - :json-rpc/call [{:method "wakuext_removeBookmark" - :params [url] - :on-success #()}]}))) + (rf/merge cofx + {:db (update db :bookmarks/bookmarks dissoc url) + :json-rpc/call [{:method "wakuext_removeBookmark" + :params [url] + :on-success #()}]})) (defn can-go-back? [{:keys [history-index]}] @@ -357,43 +353,11 @@ :id (int id) :result result}}}) -(defn utf8-to-hex - [s] - (let [hex (native-module/utf8-to-hex (str s))] - (if (empty? hex) - nil - hex))) - -(defn normalize-message - "NOTE (andrey) there is no spec for this, so this implementation just to be compatible with MM" - [message] - (if (string/starts-with? message "0x") - message - (utf8-to-hex message))) - -(defn normalize-sign-message-params - "NOTE (andrey) we need this function, because params may be mixed up" - [params typed?] - (let [[first-param second-param] params] - (when (and (string? first-param) (string? second-param)) - (cond - (address/address? first-param) - [first-param (if typed? second-param (normalize-message second-param))] - (address/address? second-param) - [second-param (if typed? first-param (normalize-message first-param))])))) - (rf/defn send-to-bridge {:events [:browser.callback/call-rpc]} [_ message] {:browser/send-to-bridge message}) -(defn web3-sign-message? - [method] - (#{constants/web3-sign-typed-data constants/web3-sign-typed-data-v3 constants/web3-sign-typed-data-v4 - constants/web3-personal-sign - constants/web3-eth-sign constants/web3-keycard-sign-typed-data} - method)) - (rf/defn handle-no-permissions [cofx {:keys [method id]} message-id] (if (= method "eth_accounts") @@ -484,18 +448,6 @@ (when (and message webview) (.injectJavaScript webview msg))))) -(re-frame/reg-fx - :browser/call-rpc - (fn [[payload callback]] - (native-module/call-rpc - (types/clj->json payload) - (fn [response] - (if (= "" response) - (do - (log/warn :web3-response-error) - (callback "web3-response-error" nil)) - (callback nil (.parse js/JSON response))))))) - (re-frame/reg-fx :browser/show-browser-selection (fn [link] @@ -548,8 +500,8 @@ (rf/defn lock-pressed {:events [:browser.ui/lock-pressed]} - [cofx secure?] - (update-browser-option cofx :show-tooltip (if secure? :secure :not-secure))) + [cofx is-secure?] + (update-browser-option cofx :show-tooltip (if is-secure? :secure :not-secure))) (rf/defn close-tooltip-pressed {:events [:browser.ui/close-tooltip-pressed]} diff --git a/src/legacy/status_im/browser/core_test.cljs b/src/legacy/status_im/browser/core_test.cljs deleted file mode 100644 index 8666631706e3..000000000000 --- a/src/legacy/status_im/browser/core_test.cljs +++ /dev/null @@ -1,120 +0,0 @@ -(ns legacy.status-im.browser.core-test - (:require - [utils.url :as url])) - -(defn has-wrong-properties? - [result dapp-url expected-browser] - (let [browser (get-in result [:db :browser/browsers dapp-url])] - (reduce (fn [acc k] - (if (= (k browser) - (k expected-browser)) - acc - (conj acc [k (str "was expecting " (k expected-browser) " got " (k browser))]))) - nil - (keys expected-browser)))) - -(defn get-dapp-id - [result dapp-url] - (some #(when (= (url/normalize-and-decode-url dapp-url) (first (:history %))) (:browser-id %)) - (vals (get-in result [:db :browser/browsers])))) - -#_(deftest browser-test - (let [dapp1-url "cryptokitties.co" - dapp2-url "http://test2.com"] - - (testing "user opens a dapp" - (let [result-open (browser/open-url {:db {} :now 1} dapp1-url) - dapp1-id (get-dapp-id result-open dapp1-url)] - (is (= dapp1-id (get-in result-open [:db :browser/options :browser-id])) - "browser-id should be dapp1-url") - (is (not (has-wrong-properties? result-open - dapp1-id - {:browser-id dapp1-id - :history-index 0 - :history ["https://cryptokitties.co"] - :dapp? false - :name (i18n/label :t/browser)})) - "some properties of the browser are not correct") - - (testing "then a second dapp" - (let [result-open-2 (browser/open-url {:db (:db result-open) - :now 2} - dapp2-url) - dapp2-id (get-dapp-id result-open-2 dapp2-url)] - (is (= dapp2-id (get-in result-open-2 [:db :browser/options :browser-id])) - "browser-id should be dapp2 host") - (is (not (has-wrong-properties? result-open-2 - dapp2-id - {:browser-id dapp2-id - :history-index 0 - :history ["http://test2.com"] - :dapp? false})) - "some properties of the browser are not correct") - - (testing "then removes the second dapp" - (let [result-remove-2 (browser/remove-browser {:db (:db result-open-2)} dapp2-id)] - (is (= #{dapp1-id} - (set (keys (get-in result-remove-2 [:db :browser/browsers])))) - "the second dapp shouldn't be in the browser list anymore"))))) - - (testing "then opens the dapp again" - (let [result-open-existing (browser/open-existing-browser {:db (:db result-open) - :now 2} - dapp1-id) - dapp1-url2 (str "https://" dapp1-url "/nav2")] - (is (not (has-wrong-properties? result-open-existing - dapp1-id - {:browser-id dapp1-id - :history-index 0 - :history ["https://cryptokitties.co"] - :dapp? false - :name (i18n/label :t/browser)})) - "some properties of the browser are not correct") - (is (nil? (browser/navigate-to-next-page result-open-existing)) - "nothing should happen if user tries to navigate to next page") - (is (nil? (browser/navigate-to-previous-page result-open-existing)) - "nothing should happen if user tries to navigate to previous page") - - (testing "then navigates to a new url in the dapp" - (let [result-navigate (browser/navigation-state-changed - {:db (:db result-open-existing) - :now 4} - (clj->js {"url" dapp1-url2 - "loading" false}) - false)] - (is (not (has-wrong-properties? result-navigate - dapp1-id - {:browser-id dapp1-id - :history-index 1 - :history ["https://cryptokitties.co" dapp1-url2] - :dapp? false - :name (i18n/label :t/browser)})) - "some properties of the browser are not correct") - - (testing "then navigates to previous page" - (let [result-previous (browser/navigate-to-previous-page {:db (:db result-navigate) - :now 5})] - (is - (not (has-wrong-properties? result-previous - dapp1-id - {:browser-id dapp1-id - :history-index 0 - :history ["https://cryptokitties.co" - dapp1-url2] - :dapp? false - :name (i18n/label :t/browser)})) - "some properties of the browser are not correct") - - (testing "then navigates to next page") - (let [result-next (browser/navigate-to-next-page {:db (:db result-previous) - :now 6})] - (is (not - (has-wrong-properties? result-next - dapp1-id - {:browser-id dapp1-id - :history-index 1 - :history ["https://cryptokitties.co" - dapp1-url2] - :dapp? false - :name (i18n/label :t/browser)})) - "some properties of the browser are not correct")))))))))))) diff --git a/src/legacy/status_im/browser/permissions.cljs b/src/legacy/status_im/browser/permissions.cljs index 893a1873f9d8..85359f187238 100644 --- a/src/legacy/status_im/browser/permissions.cljs +++ b/src/legacy/status_im/browser/permissions.cljs @@ -22,7 +22,7 @@ :icon :main-icons/wallet}}) (rf/defn permission-yield-control - [{:keys [db] :as cofx} dapp-name permission message-id params] + [cofx dapp-name permission message-id] (cond (= permission constants/dapp-permission-qr-code) (rf/merge (assoc-in cofx [:db :browser/options :yielding-control?] true) @@ -33,7 +33,7 @@ :message-id message-id}})))) (rf/defn permission-show-permission - [{:keys [db] :as cofx} dapp-name permission message-id yield-control?] + [{:keys [db]} dapp-name permission message-id yield-control?] {:db (assoc-in db [:browser/options :show-permission] {:requested-permission permission @@ -51,7 +51,7 @@ (rf/defn send-response-to-bridge "Send response to the bridge. If the permission is allowed, send data associated with the permission" - [{:keys [db] :as cofx} permission message-id allowed? data] + [_cofx permission message-id allowed? data] {:browser/send-to-bridge (cond-> {:type constants/api-response :isAllowed allowed? :permission permission @@ -108,13 +108,13 @@ (let [pending-permissions (get-in db [:browser/options :pending-permissions]) next-permission (last pending-permissions) new-cofx (update-in cofx [:db :browser/options :pending-permissions] butlast)] - (when-let [{:keys [yield-control? permission message-id allowed? params]} next-permission] + (when-let [{:keys [yield-control? permission message-id allowed?]} next-permission] (if (and yield-control? allowed?) - (permission-yield-control new-cofx dapp-name permission message-id params) + (permission-yield-control new-cofx dapp-name permission message-id) (permission-show-permission new-cofx dapp-name permission message-id yield-control?))))))) (rf/defn send-response-and-process-next-permission - [{:keys [db] :as cofx} dapp-name requested-permission message-id] + [cofx dapp-name requested-permission message-id] (rf/merge cofx (send-response-to-bridge requested-permission message-id @@ -126,12 +126,12 @@ "Add permission to set of allowed permission and process next permission" {:events [:browser.permissions.ui/dapp-permission-allowed]} [{:keys [db] :as cofx}] - (let [{:keys [requested-permission message-id dapp-name yield-control? params]} + (let [{:keys [requested-permission message-id dapp-name yield-control?]} (get-in db [:browser/options :show-permission])] (rf/merge (assoc-in cofx [:db :browser/options :show-permission] nil) (update-dapp-permissions dapp-name requested-permission true) (if yield-control? - (permission-yield-control dapp-name requested-permission message-id params) + (permission-yield-control dapp-name requested-permission message-id) (send-response-and-process-next-permission dapp-name requested-permission message-id))))) (rf/defn deny-permission diff --git a/src/legacy/status_im/browser/permissions_test.cljs b/src/legacy/status_im/browser/permissions_test.cljs deleted file mode 100644 index 0ba8e76fcf25..000000000000 --- a/src/legacy/status_im/browser/permissions_test.cljs +++ /dev/null @@ -1,90 +0,0 @@ -(ns legacy.status-im.browser.permissions-test) - -#_(deftest permissions-test - (let [dapp-name "test.com" - dapp-name2 "test2.org" - cofx {:db (assoc-in (:db (browser/open-url {:db {}} dapp-name)) - [:profile/profile :public-key] - "public-key")} - dapp-id (core.tests/get-dapp-id cofx dapp-name)] - (testing "dapps permissions are initialized" - (is (zero? (count (get-in cofx [:db :dapps/permissions])))) - (is (= dapp-id (get-in cofx [:db :browser/options :browser-id])))) - - (testing "receiving an unsupported permission" - (let [result-ask (browser/process-bridge-message cofx - (types/clj->json - {:type "api-request" - :host dapp-name - :messageId 0 - :permission "FAKE_PERMISSION"}))] - (is (not (get-in result-ask [:browser/send-to-bridge :isAllowed]))))) - - (testing "receiving a supported permission" - (let [result-ask (browser/process-bridge-message cofx - (types/clj->json {:type "api-request" - :host dapp-name - :messageId 1 - :permission "contact-code"}))] - (is (= (get-in result-ask [:db :browser/options :show-permission]) - {:requested-permission "contact-code" - :dapp-name "test.com" - :message-id 1 - :yield-control? nil})) - (is (zero? (count (get-in result-ask [:db :dapps/permissions])))) - - (testing "then user accepts the supported permission" - (let [accept-result (permissions/allow-permission {:db (:db result-ask)})] - (is (= (get accept-result :browser/send-to-bridge) - {:type "api-response" - :messageId 1 - :isAllowed true - :data "public-key" - :permission "contact-code"}) - "the data should have been sent to the bridge") - (is (= (get-in accept-result [:db :dapps/permissions]) - {"test.com" {:dapp "test.com" :permissions ["contact-code"]}}) - "the dapp should now have CONTACT_CODE permission") - - (testing "then dapp asks for permission again" - (let [result-ask-again (browser/process-bridge-message {:db (:db accept-result)} - (types/clj->json - {:type "api-request" - :host dapp-name - :messageId 2 - :permission "contact-code"}))] - (is (= (get result-ask-again :browser/send-to-bridge) - {:type "api-response" - :isAllowed true - :messageId 2 - :data "public-key" - :permission "contact-code"}) - "the response should be immediatly sent to the bridge"))) - - (testing "then user switch to another dapp that asks for permissions" - (let [new-dapp (browser/open-url {:db (:db accept-result)} dapp-name2) - result-ask2 (browser/process-bridge-message {:db (:db new-dapp)} - (types/clj->json - {:type "api-request" - :host dapp-name2 - :messageId 3 - :permission "contact-code"}))] - (is (= (get-in result-ask2 [:db :dapps/permissions]) - {"test.com" {:dapp "test.com" :permissions ["contact-code"]}}) - "there should only be permissions for dapp-name at that point") - (is (nil? (get result-ask2 :browser/send-to-bridge)) - "no message should be sent to the bridge") - - (testing "then user accepts permission for dapp-name2" - (let [accept-result2 (permissions/allow-permission {:db (:db result-ask2)})] - (is (= (get-in accept-result2 [:db :dapps/permissions]) - {"test.com" {:dapp "test.com" :permissions ["contact-code"]} - "test2.org" {:dapp "test2.org" :permissions ["contact-code"]}}) - "there should be permissions for both dapps now") - (is (= (get accept-result2 :browser/send-to-bridge) - {:type "api-response" - :isAllowed true - :messageId 3 - :data "public-key" - :permission "contact-code"}) - "the response should be sent to the bridge"))))))))))) diff --git a/src/legacy/status_im/chat/models/mentions.cljs b/src/legacy/status_im/chat/models/mentions.cljs index 2a8db93264ab..12e1152aeb43 100644 --- a/src/legacy/status_im/chat/models/mentions.cljs +++ b/src/legacy/status_im/chat/models/mentions.cljs @@ -156,7 +156,7 @@ (rf/defn select-mention {:events [:chat.ui/select-mention]} - [{:keys [db]} {:keys [primary-name searched-text match public-key] :as user}] + [{:keys [db]} {:keys [primary-name searched-text match public-key] :as _user}] (let [chat-id (:current-chat-id db) text (get-in db [:chat/inputs chat-id :input-text]) method "wakuext_chatMentionSelectMention" diff --git a/src/legacy/status_im/chat/models/message.cljs b/src/legacy/status_im/chat/models/message.cljs index c90f5091404a..ca3cf5b598cd 100644 --- a/src/legacy/status_im/chat/models/message.cljs +++ b/src/legacy/status_im/chat/models/message.cljs @@ -120,7 +120,7 @@ {:db (assoc-in db [:messages chat-id message-id :outgoing-status] status)})) (rf/defn handle-removed-messages - [{:keys [db] :as cofx} removed-messages] + [cofx removed-messages] (let [mark-as-deleted-fx (->> removed-messages (map #(assoc % :message-id (:messageId %) @@ -136,7 +136,7 @@ [message-id] nil))) removed-messages) - remove-messages-fx (fn [{:keys [db]}] + remove-messages-fx (fn [_cofx] {:dispatch [:activity-center.notifications/fetch-unread-count]})] (apply rf/merge cofx diff --git a/src/legacy/status_im/communities/core.cljs b/src/legacy/status_im/communities/core.cljs index 0b2e3492fb00..ddcc3d12b25e 100644 --- a/src/legacy/status_im/communities/core.cljs +++ b/src/legacy/status_im/communities/core.cljs @@ -43,7 +43,7 @@ (rf/defn member-ban {:events [::member-ban]} - [cofx community-id public-key] + [_cofx community-id public-key] {:json-rpc/call [{:method "wakuext_banUserFromCommunity" :params [{:communityId community-id :user public-key}] @@ -63,7 +63,7 @@ (rf/defn member-kick {:events [::member-kick]} - [cofx community-id public-key] + [_cofx community-id public-key] {:json-rpc/call [{:method "wakuext_removeUserFromCommunity" :params [community-id public-key] :js-response true @@ -97,7 +97,7 @@ (rf/defn add-role-to-member {:events [:community.member/add-role]} - [cofx community-id public-key role-id] + [_cofx community-id public-key role-id] {:json-rpc/call [{:method "wakuext_addRoleToMember" :params [{:communityId community-id :user public-key diff --git a/src/legacy/status_im/data_store/communities.cljs b/src/legacy/status_im/data_store/communities.cljs index 65086ffa3153..9e7b1d42a91d 100644 --- a/src/legacy/status_im/data_store/communities.cljs +++ b/src/legacy/status_im/data_store/communities.cljs @@ -4,12 +4,6 @@ [status-im.constants :as constants] [utils.transforms :as transforms])) -(defn <-revealed-accounts-rpc - [accounts] - (mapv - #(set/rename-keys % {:isAirdropAddress :airdrop-address?}) - (js->clj accounts :keywordize-keys true))) - (defn <-request-to-join-community-rpc [r] (set/rename-keys r diff --git a/src/legacy/status_im/data_store/messages.cljs b/src/legacy/status_im/data_store/messages.cljs index e8b28089b1df..7a20d0b63fe0 100644 --- a/src/legacy/status_im/data_store/messages.cljs +++ b/src/legacy/status_im/data_store/messages.cljs @@ -16,7 +16,7 @@ :community-id :communityId :clock-value :clock}))) -(defn- <-status-link-previews-rpc +(defn <-status-link-previews-rpc [preview] (-> preview (update :community @@ -40,7 +40,7 @@ (update-in [:community :banner] set/rename-keys {:data-uri :dataUri}) (update-in [:community :icon] set/rename-keys {:data-uri :dataUri}))) -(defn- <-link-preview-rpc +(defn <-link-preview-rpc [preview] (-> preview (update :thumbnail set/rename-keys {:dataUri :data-uri}) @@ -160,17 +160,17 @@ :on-error #(log/error "failed to delete messages by chat-id" % chat-id)}]}) (rf/defn delete-message - [cofx id] + [_cofx id] (delete-message-rpc id)) (rf/defn delete-messages-from - [cofx author] + [_cofx author] (delete-messages-from-rpc author)) (rf/defn mark-messages-seen - [cofx chat-id ids on-success] + [_cofx chat-id ids on-success] (mark-seen-rpc chat-id ids on-success)) (rf/defn delete-messages-by-chat-id - [cofx chat-id] + [_cofx chat-id] (delete-messages-by-chat-id-rpc chat-id)) diff --git a/src/legacy/status_im/data_store/pin_messages.cljs b/src/legacy/status_im/data_store/pin_messages.cljs index 833389255c47..d90103bf4914 100644 --- a/src/legacy/status_im/data_store/pin_messages.cljs +++ b/src/legacy/status_im/data_store/pin_messages.cljs @@ -29,7 +29,7 @@ :on-error on-error}]}) (rf/defn send-pin-message - [cofx pin-message] + [_cofx pin-message] {:json-rpc/call [{:method "wakuext_sendPinMessage" :params [(messages/->rpc pin-message)] :js-response true diff --git a/src/legacy/status_im/ens/core.cljs b/src/legacy/status_im/ens/core.cljs index b302498b973c..534d380cbe68 100644 --- a/src/legacy/status_im/ens/core.cljs +++ b/src/legacy/status_im/ens/core.cljs @@ -62,7 +62,7 @@ (rf/defn update-ens-tx-state-and-redirect {:events [:update-ens-tx-state-and-redirect]} - [{:keys [db] :as cofx} new-state username custom-domain? tx-hash] + [cofx new-state username custom-domain? tx-hash] (rf/merge cofx (update-ens-tx-state new-state username custom-domain? tx-hash) (redirect-to-ens-summary))) @@ -178,13 +178,6 @@ :else (re-frame/dispatch [::name-resolved username :taken])))) -(defn registration-cost - [chain-id] - (case chain-id - 3 50 - 5 10 - 1 10)) - (rf/defn register-name {:events [::register-name-pressed]} [{:keys [db]} address] @@ -239,14 +232,14 @@ (let [{:keys [custom-domain?]} (:ens/registration db) chain-id (chain/chain-id db) usernames (into #{} (keys (get-in db [:ens/names chain-id]))) - state (state custom-domain? username usernames)] + next-state (state custom-domain? username usernames)] (reset! resolve-last-id (random/id)) (merge {:db (update db :ens/registration assoc :username username - :state state)} - (when (= state :searching) + :state next-state)} + (when (= next-state :searching) (let [{:profile/keys [profile]} db {:keys [public-key]} profile addresses (addresses-without-watch db) diff --git a/src/legacy/status_im/ethereum/macros.clj b/src/legacy/status_im/ethereum/macros.clj index cec627223024..447c3842669a 100644 --- a/src/legacy/status_im/ethereum/macros.clj +++ b/src/legacy/status_im/ethereum/macros.clj @@ -1,28 +1,6 @@ (ns legacy.status-im.ethereum.macros (:require - [clojure.java.io :as io] - [clojure.string :as string])) - -(defn token-icon-path - [path] - (fn [el] - (let [el (string/replace el ".png" "") - s (str path el ".png") - s-js (str "." s)] - (when (.exists (io/file s)) - [el `(js/require ~s-js)])))) - -(defmacro resolve-icons - "In react-native arguments to require must be static strings. - Resolve all icons at compilation time so no variable is used." - [network] - (let [path (str "./resources/images/tokens/" (name network) "/") - files (->> (io/file path) - file-seq - (filter #(string/ends-with? % "png")) - (map #(first (string/split (.getName %) #"@"))) - distinct)] - (into {} (map (token-icon-path path) files)))) + [clojure.java.io :as io])) (defn network->icon [network] diff --git a/src/legacy/status_im/ethereum/tokens.cljs b/src/legacy/status_im/ethereum/tokens.cljs index 20f51535d82e..c9e8c7c867d0 100644 --- a/src/legacy/status_im/ethereum/tokens.cljs +++ b/src/legacy/status_im/ethereum/tokens.cljs @@ -1,8 +1,7 @@ (ns legacy.status-im.ethereum.tokens (:require - [clojure.string :as string] [utils.ethereum.chain :as chain]) - (:require-macros [legacy.status-im.ethereum.macros :as ethereum.macros :refer [resolve-icons]])) + (:require-macros [legacy.status-im.ethereum.macros :as ethereum.macros])) (def default-native-currency (memoize @@ -13,8 +12,6 @@ :decimals 18 :icon {:source (js/require "../resources/images/tokens/default-token.png")}}))) -(def snt-icon-source (js/require "../resources/images/tokens/mainnet/SNT.png")) - (def all-native-currencies (ethereum.macros/resolve-native-currency-icons {:mainnet {:name "Ether" @@ -38,54 +35,8 @@ :symbol-display :BNBtest :decimals 18}})) -(def native-currency-symbols - (set (map #(-> % val :symbol) all-native-currencies))) - (defn native-currency [{sym :symbol :as current-network}] (let [chain (chain/network->chain-keyword current-network)] (get all-native-currencies chain (default-native-currency sym)))) -(defn ethereum? - [sym] - (native-currency-symbols sym)) - -(def token-icons - {:mainnet (resolve-icons :mainnet) - :xdai (resolve-icons :xdai) - :custom []}) - -(def default-token (js/require "../resources/images/tokens/default-token.png")) - -(defn update-icon - [network token] - (-> token - (assoc-in [:icon :source] (get-in token-icons [network (name (:symbol token))] default-token)) - (update :address string/lower-case))) - -(defn nfts-for - [all-tokens] - (filter :nft? (vals all-tokens))) - -(defn sorted-tokens-for - [all-tokens] - (->> (vals all-tokens) - (filter #(not (:hidden? %))) - (sort #(compare (string/lower-case (:name %1)) - (string/lower-case (:name %2)))))) - -(defn symbol->token - [all-tokens sym] - (some #(when (= sym (:symbol %)) %) (vals all-tokens))) - -(defn address->token - [all-tokens address] - (get all-tokens (string/lower-case address))) - -(defn asset-for - [all-tokens current-network sym] - (let [native-coin (native-currency current-network)] - (if (or (= (:symbol-display native-coin) sym) - (= (:symbol native-coin) sym)) - native-coin - (symbol->token all-tokens sym)))) diff --git a/src/legacy/status_im/ethereum/transactions/core.cljs b/src/legacy/status_im/ethereum/transactions/core.cljs index 57039ddfae1e..a51a2cd94cbc 100644 --- a/src/legacy/status_im/ethereum/transactions/core.cljs +++ b/src/legacy/status_im/ethereum/transactions/core.cljs @@ -7,37 +7,9 @@ [re-frame.core :as re-frame] [status-im.common.json-rpc.events :as json-rpc] [taoensso.timbre :as log] - [utils.ethereum.chain :as chain] [utils.ethereum.eip.eip55 :as eip55] [utils.re-frame :as rf])) -(def confirmations-count-threshold 12) - -(def etherscan-supported? - #{(chain/chain-keyword->chain-id :mainnet) - (chain/chain-keyword->chain-id :sepolia)}) - -(def binance-mainnet-chain-id (chain/chain-keyword->chain-id :bsc)) -(def binance-testnet-chain-id (chain/chain-keyword->chain-id :bsc-testnet)) - -(def network->subdomain {11155111 "sepolia"}) - -(defn get-transaction-details-url - [chain-id tx-hash] - {:pre [(number? chain-id) (string? tx-hash)] - :post [(or (nil? %) (string? %))]} - (cond - (etherscan-supported? chain-id) - (let [network-subdomain (when-let [subdomain (network->subdomain chain-id)] - (str subdomain "."))] - (str "https://" network-subdomain "etherscan.io/tx/" tx-hash)) - - (= chain-id binance-mainnet-chain-id) - (str "https://bscscan.com/tx/" tx-hash) - - (= chain-id binance-testnet-chain-id) - (str "https://testnet.bscscan.com/tx/" tx-hash))) - (def default-erc20-token {:symbol :ERC20 :decimals 18 @@ -121,16 +93,16 @@ (rf/defn check-transaction "Check if the transaction has been triggered and applies the effects returned by `on-trigger` if that is the case" - [{:keys [db] :as cofx} {:keys [hash] :as transaction}] + [{:keys [db] :as cofx} {tx-hash :hash :as transaction}] (when-let [watch-params - (get-in db [:ethereum/watched-transactions hash])] + (get-in db [:ethereum/watched-transactions tx-hash])] (let [{:keys [trigger-fn on-trigger]} watch-params] (when (trigger-fn db transaction) (rf/merge cofx {:db (update db :ethereum/watched-transactions dissoc - hash)} + tx-hash)} (on-trigger transaction)))))) (rf/defn check-watched-transactions @@ -152,14 +124,14 @@ "We determine a unique id for the transfer before adding it because some transaction can contain multiple transfers and they would overwrite each other in the transfer map if identified by hash" - [{:keys [db] :as cofx} {:keys [hash id address] :as transfer}] - (let [transfer-by-hash (get-in db [:wallet-legacy :accounts address :transactions hash])] + [{:keys [db] :as cofx} {tx-hash :hash :keys [id address] :as transfer}] + (let [transfer-by-hash (get-in db [:wallet-legacy :accounts address :transactions tx-hash])] (when-let [unique-id (when-not (= transfer transfer-by-hash) (if (and transfer-by-hash (not (= :pending (:type transfer-by-hash)))) id - hash))] + tx-hash))] (rf/merge cofx {:db (assoc-in db [:wallet-legacy :accounts address :transactions unique-id] @@ -170,11 +142,7 @@ [db address] (get-in db [:wallet-legacy :accounts (eip55/address->checksum address) :min-block])) -(defn get-max-block-with-transfers - [db address] - (get-in db [:wallet-legacy :accounts (eip55/address->checksum address) :max-block])) - -(defn min-block-transfers-count +(defn count-min-block-transfers [db address] (get-in db [:wallet-legacy :accounts @@ -187,14 +155,14 @@ {:keys [min-block min-block-transfers-count]} (reduce (fn [{:keys [min-block] :as acc} - {:keys [block hash]}] + {tx-hash :hash block :block}] (cond (or (nil? min-block) (> min-block (js/parseInt block))) {:min-block (js/parseInt block) :min-block-transfers-count 1} (and (= min-block block) - (nil? (get-in db [:wallet-legacy :accounts checksum :transactions hash]))) + (nil? (get-in db [:wallet-legacy :accounts checksum :transactions tx-hash]))) (update acc :min-block-transfers-count inc) :else acc)) @@ -203,7 +171,7 @@ (js/parseInt min-block-string)) :min-block-transfers-count - (min-block-transfers-count db address)} + (count-min-block-transfers db address)} transfers)] (log/debug "[transactions] set-lowest-fetched-block" "address" address @@ -238,7 +206,7 @@ {:db (update-fetching-status db addresses :history? false)}) (rf/defn tx-history-end-reached - [{:keys [db] :as cofx} address] + [{:keys [db]} address] (let [syncing-allowed? (utils.mobile-sync/syncing-allowed? db)] {:db (assoc-in db [:wallet-legacy :fetching address :all-fetched?] @@ -247,23 +215,22 @@ :all-preloaded))})) (rf/defn handle-new-transfer - [{:keys [db] :as cofx} transfers {:keys [address limit]}] + [cofx transfers {:keys [address limit]}] (log/debug "[transfers] new-transfers" "address" address "count" (count transfers) "limit" limit) - (let [checksum (eip55/address->checksum address) - max-known-block (get-max-block-with-transfers db address) - effects (cond-> [(when (seq transfers) - (set-lowest-fetched-block checksum transfers))] + (let [checksum (eip55/address->checksum address) + effects (cond-> [(when (seq transfers) + (set-lowest-fetched-block checksum transfers))] - (seq transfers) - (concat - [] - (mapv add-transfer transfers)) + (seq transfers) + (concat + [] + (mapv add-transfer transfers)) - (< (count transfers) limit) - (conj (tx-history-end-reached checksum)))] + (< (count transfers) limit) + (conj (tx-history-end-reached checksum)))] (apply rf/merge cofx (tx-fetching-ended [checksum]) effects))) (rf/defn new-transfers @@ -311,16 +278,12 @@ :limit limit)]) :on-error #(re-frame/dispatch [::tx-fetching-failed address])}))))) -(defn some-transactions-loaded? - [db address] - (not-empty (get-in db [:wallet-legacy :accounts address :transactions]))) - (rf/defn fetch-more-tx {:events [:transactions/fetch-more]} [{:keys [db] :as cofx} address] - (let [min-known-block (or (get-min-known-block db address) - (:ethereum/current-block db)) - min-block-transfers-count (or (min-block-transfers-count db address) 0)] + (let [min-known-block (or (get-min-known-block db address) + (:ethereum/current-block db)) + min-count (or (count-min-block-transfers db address) 0)] (rf/merge cofx {:transactions/get-transfers @@ -333,7 +296,7 @@ ;; the whole `default-transfers-limit` of transfers the number of transfers already received ;; for `min-known-block` is added to the page size. :limit-per-address {address (+ default-transfers-limit - min-block-transfers-count)}}} + min-count)}}} (tx-fetching-in-progress [address])))) (rf/defn get-fetched-transfers diff --git a/src/legacy/status_im/events.cljs b/src/legacy/status_im/events.cljs index 90afefe6a8d7..d8a6046ad912 100644 --- a/src/legacy/status_im/events.cljs +++ b/src/legacy/status_im/events.cljs @@ -59,21 +59,11 @@ (fn [options] (permissions/request-notifications options))) -(re-frame/reg-fx - :ui/show-error - (fn [content] - (utils/show-popup "Error" content))) - (re-frame/reg-fx :ui/show-confirmation (fn [options] (utils/show-confirmation options))) -(re-frame/reg-fx - :ui/close-application - (fn [_] - (native-module/close-application))) - (re-frame/reg-fx ::app-state-change-fx (fn [state] @@ -83,11 +73,6 @@ (theme/change-device-theme (rn/get-color-scheme))) (native-module/app-state-change state))) -(re-frame/reg-fx - :ui/listen-to-window-dimensions-change - (fn [] - (dimensions/add-event-listener))) - (rf/defn dismiss-keyboard {:events [:dismiss-keyboard]} [_] @@ -233,7 +218,4 @@ :on-success (fn [on-ramps] (re-frame/dispatch [::crypto-loaded on-ramps]))}]}) -(re-frame/reg-event-fx :buy-crypto.ui/open-screen - (fn [] - {:fx [[:dispatch [:wallet-legacy/keep-watching]] - [:dispatch [:open-modal :buy-crypto nil]]]})) + diff --git a/src/legacy/status_im/fleet/core.cljs b/src/legacy/status_im/fleet/core.cljs index d504f791bef3..b08b42a1b62a 100644 --- a/src/legacy/status_im/fleet/core.cljs +++ b/src/legacy/status_im/fleet/core.cljs @@ -84,7 +84,7 @@ (rf/defn save {:events [:fleet.ui/save-fleet-confirmed]} - [{:keys [db now] :as cofx} fleet] + [{:keys [db] :as cofx} fleet] (let [old-fleet (get-in db [:profile/profile :fleet])] (when (not= fleet old-fleet) (multiaccounts.update/multiaccount-update diff --git a/src/legacy/status_im/group_chats/core.cljs b/src/legacy/status_im/group_chats/core.cljs index e77b534486f4..a2479cd89045 100644 --- a/src/legacy/status_im/group_chats/core.cljs +++ b/src/legacy/status_im/group_chats/core.cljs @@ -40,7 +40,7 @@ (rf/defn remove-member "Format group update message and sign membership" {:events [:group-chats.ui/remove-member-pressed]} - [_ chat-id member do-not-navigate?] + [_ chat-id member _do-not-navigate?] {:json-rpc/call [{:method "wakuext_removeMemberFromGroupChat" :params [nil chat-id member] :js-response true @@ -48,7 +48,7 @@ (rf/defn remove-members {:events [:group-chats.ui/remove-members-pressed]} - [{{:group-chat/keys [deselected-members]} :db :as cofx} chat-id] + [{{:group-chat/keys [deselected-members]} :db :as _cofx} chat-id] {:json-rpc/call [{:method "wakuext_removeMembersFromGroupChat" :params [nil chat-id deselected-members] :js-response true @@ -104,7 +104,7 @@ (rf/defn leave "Leave chat" {:events [:group-chats.ui/leave-chat-confirmed]} - [{:keys [db] :as cofx} chat-id] + [_cofx chat-id] {:json-rpc/call [{:method "wakuext_leaveGroupChat" :params [nil chat-id true] :js-response true @@ -128,7 +128,7 @@ (rf/defn name-changed "Save chat from edited profile" {:events [:group-chats.ui/name-changed]} - [{:keys [db] :as cofx} chat-id new-name] + [{:keys [db] :as _cofx} chat-id new-name] (when (valid-name? new-name) {:db (assoc-in db [:chats chat-id :name] new-name) :json-rpc/call [{:method "wakuext_changeGroupChatName" @@ -149,7 +149,7 @@ (rf/defn send-group-chat-membership-request "Send group chat membership request" {:events [:send-group-chat-membership-request]} - [{{:keys [chats] :as db} :db :as cofx} chat-id] + [{{:keys [chats] :as db} :db :as _cofx} chat-id] (let [{:keys [invitation-admin]} (get chats chat-id) message (get-in db [:chat/memberships chat-id :message])] {:db (assoc-in db [:chat/memberships chat-id] nil) @@ -161,7 +161,7 @@ (rf/defn send-group-chat-membership-rejection "Send group chat membership rejection" {:events [:send-group-chat-membership-rejection]} - [cofx invitation-id] + [_cofx invitation-id] {:json-rpc/call [{:method "wakuext_sendGroupChatInvitationRejection" :params [nil invitation-id] :js-response true @@ -176,15 +176,6 @@ % invitations))}) -(defn member-removed? - [{:keys [membership-update-events]} pk] - (->> membership-update-events - (filter #(contains? (set (:members %)) pk)) - (sort-by :clockValue >) - first - :type - (= constants/invitation-state-removed))) - (rf/defn deselect-member {:events [:deselect-member]} [{:keys [db]} id] diff --git a/src/legacy/status_im/group_chats/db.cljs b/src/legacy/status_im/group_chats/db.cljs deleted file mode 100644 index 09ca7ed8d8df..000000000000 --- a/src/legacy/status_im/group_chats/db.cljs +++ /dev/null @@ -1,26 +0,0 @@ -(ns legacy.status-im.group-chats.db) - -(def members-added-type 3) - -(defn member? - [public-key {:keys [members contacts users]}] - (let [members-list (into #{} (concat (keys users) contacts (map #(:id %) members)))] - (contains? members-list public-key))) - -(defn invited? - [my-public-key {:keys [contacts]}] - (contains? contacts my-public-key)) - -(defn get-inviter-pk - [my-public-key {:keys [membership-update-events]}] - (->> membership-update-events - reverse - (keep (fn [{:keys [from type members]}] - (when (and (= type members-added-type) - ((set members) my-public-key)) - from))) - first)) - -(defn group-chat? - [chat] - (and (:group-chat chat) (not (:public? chat)))) diff --git a/src/legacy/status_im/log_level/core.cljs b/src/legacy/status_im/log_level/core.cljs index 1f865a00bdc3..c1538ae855ac 100644 --- a/src/legacy/status_im/log_level/core.cljs +++ b/src/legacy/status_im/log_level/core.cljs @@ -7,7 +7,7 @@ (rf/defn save-log-level {:events [:log-level.ui/change-log-level-confirmed]} - [{:keys [db now] :as cofx} log-level] + [{:keys [db] :as cofx} log-level] (let [old-log-level (get-in db [:profile/profile :log-level])] (when (not= old-log-level log-level) (multiaccounts.update/multiaccount-update diff --git a/src/legacy/status_im/mailserver/constants.cljs b/src/legacy/status_im/mailserver/constants.cljs deleted file mode 100644 index 5f9054e65122..000000000000 --- a/src/legacy/status_im/mailserver/constants.cljs +++ /dev/null @@ -1,18 +0,0 @@ -(ns ^{:doc "Mailserver events and API"} legacy.status-im.mailserver.constants) - -(def one-day (* 24 3600)) -(def seven-days (* 7 one-day)) -(def max-gaps-range (* 30 one-day)) -(def max-request-range one-day) -(def maximum-number-of-attempts 2) -(def request-timeout 30) -(def min-limit 100) -(def max-limit 1000) -(def backoff-interval-ms 3000) -(def default-limit max-limit) -;; If a mailserver fails, how long before we should consider them again -;; for selection, in ms -(def cooloff-period 120000) -(def connection-timeout - "Time after which mailserver connection is considered to have failed" - 10000) diff --git a/src/legacy/status_im/multiaccounts/create/core.cljs b/src/legacy/status_im/multiaccounts/create/core.cljs index af59e96715e8..270b418fa33d 100644 --- a/src/legacy/status_im/multiaccounts/create/core.cljs +++ b/src/legacy/status_im/multiaccounts/create/core.cljs @@ -1,7 +1,6 @@ (ns legacy.status-im.multiaccounts.create.core (:require [legacy.status-im.utils.deprecated-types :as types] - [legacy.status-im.utils.signing-phrase.core :as signing-phrase] [native-module.core :as native-module] [re-frame.core :as re-frame] [status-im.constants :as constants] @@ -29,11 +28,6 @@ derived (update :derived normalize-derived-data-keys))) -(re-frame/reg-cofx - ::get-signing-phrase - (fn [cofx _] - (assoc cofx :signing-phrase (signing-phrase/generate)))) - (re-frame/reg-fx :multiaccount-generate-and-derive-addresses (fn [] diff --git a/src/legacy/status_im/multiaccounts/recover/core.cljs b/src/legacy/status_im/multiaccounts/recover/core.cljs deleted file mode 100644 index d1c08f30b8fd..000000000000 --- a/src/legacy/status_im/multiaccounts/recover/core.cljs +++ /dev/null @@ -1,31 +0,0 @@ -(ns legacy.status-im.multiaccounts.recover.core - (:require - [legacy.status-im.multiaccounts.create.core :as multiaccounts.create] - [legacy.status-im.utils.deprecated-types :as types] - [native-module.core :as native-module] - [re-frame.core :as re-frame] - [status-im.constants :as constants] - [taoensso.timbre :as log])) - -(re-frame/reg-fx - ::import-multiaccount - (fn [{:keys [passphrase password success-event]}] - (log/debug "[recover] ::import-multiaccount") - (native-module/multiaccount-import-mnemonic - passphrase - password - (fn [result] - (let [{:keys [id] :as root-data} - (multiaccounts.create/normalize-multiaccount-data-keys - (types/json->clj result))] - (native-module.core/multiaccount-derive-addresses - id - [constants/path-wallet-root - constants/path-eip1581 - constants/path-whisper - constants/path-default-wallet] - (fn [result] - (let [derived-data (multiaccounts.create/normalize-derived-data-keys - (types/json->clj result))] - (re-frame/dispatch [success-event root-data derived-data]))))))))) - diff --git a/src/legacy/status_im/multiaccounts/reset_password/core.cljs b/src/legacy/status_im/multiaccounts/reset_password/core.cljs deleted file mode 100644 index f0beac48146d..000000000000 --- a/src/legacy/status_im/multiaccounts/reset_password/core.cljs +++ /dev/null @@ -1,94 +0,0 @@ -(ns legacy.status-im.multiaccounts.reset-password.core - (:require - [clojure.string :as string] - [legacy.status-im.popover.core :as popover] - [legacy.status-im.utils.deprecated-types :as types] - [native-module.core :as native-module] - [re-frame.core :as re-frame] - [utils.re-frame :as rf] - [utils.security.core :as security])) - -(rf/defn on-input-change - {:events [::handle-input-change]} - [{:keys [db]} input-id value] - (let [new-password (get-in db [:multiaccount/reset-password-form-vals :new-password]) - error (when (and (= input-id :confirm-new-password) - (pos? (count new-password)) - (pos? (count value)) - (not= value new-password)) - :t/password-mismatch)] - {:db (-> db - (assoc-in [:multiaccount/reset-password-form-vals input-id] value) - (assoc-in [:multiaccount/reset-password-errors input-id] error))})) - -(rf/defn clear-form-vals - {:events [::clear-form-vals]} - [{:keys [db]}] - {:db (dissoc db :multiaccount/reset-password-form-vals :multiaccount/reset-password-errors)}) - -(rf/defn set-current-password-error - {:events [::handle-verification-error ::password-reset-error]} - [{:keys [db]} error] - {:db (assoc-in db [:multiaccount/reset-password-errors :current-password] error)}) - -(rf/defn password-reset-success - {:events [::password-reset-success]} - [{:keys [db] :as cofx}] - (rf/merge cofx - {:db (dissoc - db - :multiaccount/reset-password-form-vals - :multiaccount/reset-password-errors - :multiaccount/reset-password-next-enabled? - :multiaccount/resetting-password?)})) - -(defn change-db-password-cb - [res] - (let [{:keys [error]} (types/json->clj res)] - (if (not (string/blank? error)) - (re-frame/dispatch [::password-reset-error error]) - (re-frame/dispatch [::password-reset-success])))) - -(re-frame/reg-fx - ::change-db-password - (fn [[key-uid {:keys [current-password new-password]}]] - (native-module/reset-password - key-uid - (native-module/sha3 (security/safe-unmask-data current-password)) - (native-module/sha3 (security/safe-unmask-data new-password)) - change-db-password-cb))) - -(rf/defn handle-verification-success - {:events [::handle-verification-success]} - [{:keys [db] :as cofx} form-vals] - (let [{:keys [key-uid name]} (:profile/profile db)] - (rf/merge cofx - {::change-db-password [key-uid form-vals] - :db (assoc db - :multiaccount/resetting-password? - true)} - (popover/show-popover {:view :password-reset-popover - :prevent-closing? true})))) - -(defn handle-verification - [form-vals result] - (let [{:keys [error]} (types/json->clj result)] - (if (not (string/blank? error)) - (re-frame/dispatch [::handle-verification-error :t/wrong-password]) - (re-frame/dispatch [::handle-verification-success form-vals])))) - -(re-frame/reg-fx - ::validate-current-password-and-reset - (fn [{:keys [address current-password] :as form-vals}] - (let [hashed-pass (native-module/sha3 (security/safe-unmask-data current-password))] - (native-module/verify address - hashed-pass - (partial handle-verification form-vals))))) - -(rf/defn reset - {:events [::reset]} - [{:keys [db]} form-vals] - {::validate-current-password-and-reset - (assoc form-vals - :address - (get-in db [:profile/profile :wallet-root-address]))}) diff --git a/src/legacy/status_im/multiaccounts/update/core.cljs b/src/legacy/status_im/multiaccounts/update/core.cljs index b187b30cf1f4..12dcd3c2b5eb 100644 --- a/src/legacy/status_im/multiaccounts/update/core.cljs +++ b/src/legacy/status_im/multiaccounts/update/core.cljs @@ -9,7 +9,7 @@ (rf/defn send-contact-update [{:keys [db]}] - (let [{:keys [name preferred-name display-name address]} (:profile/profile db)] + (let [{:keys [name preferred-name display-name]} (:profile/profile db)] {:json-rpc/call [{:method "wakuext_sendContactUpdates" :params [(or preferred-name display-name name) "" ""] :on-success #(log/debug "sent contact update")}]})) @@ -79,30 +79,27 @@ synced-stickers)) (rf/defn optimistic - [{:keys [db] :as cofx} setting setting-value] - (let [current-multiaccount (:profile/profile db) - setting-value (if (= :currency setting) - (settings/rpc->currency setting-value) - setting-value) - db (case setting - :stickers/packs-pending - (let [packs-pending (keys (js->clj setting-value))] - (update db :stickers/packs-pending conj packs-pending)) - :stickers/packs-installed - (let [packs-installed-keys (keys (js->clj setting-value))] - (reduce #(assoc-in %1 - [:stickers/packs %2 :status] - constants/sticker-pack-status-installed) - db - packs-installed-keys)) - :stickers/recent-stickers - (let [recent-stickers-from-remote (augment-synchronized-recent-stickers - (types/js->clj setting-value) - (:stickers/packs db)) - merged (into recent-stickers-from-remote - (:stickers/recent-stickers db))] - (assoc db :stickers/recent-stickers recent-stickers-from-remote)) - db)] + [{:keys [db]} setting setting-value] + (let [setting-value (if (= :currency setting) + (settings/rpc->currency setting-value) + setting-value) + db (case setting + :stickers/packs-pending + (let [packs-pending (keys (js->clj setting-value))] + (update db :stickers/packs-pending conj packs-pending)) + :stickers/packs-installed + (let [packs-installed-keys (keys (js->clj setting-value))] + (reduce #(assoc-in %1 + [:stickers/packs %2 :status] + constants/sticker-pack-status-installed) + db + packs-installed-keys)) + :stickers/recent-stickers + (let [recent-stickers-from-remote (augment-synchronized-recent-stickers + (types/js->clj setting-value) + (:stickers/packs db))] + (assoc db :stickers/recent-stickers recent-stickers-from-remote)) + db)] {:db (if setting-value (assoc-in db [:profile/profile setting] setting-value) (update db :profile/profile dissoc setting)) diff --git a/src/legacy/status_im/node/core.cljs b/src/legacy/status_im/node/core.cljs index e24bd8930793..cb3e60665e2c 100644 --- a/src/legacy/status_im/node/core.cljs +++ b/src/legacy/status_im/node/core.cljs @@ -1,7 +1,6 @@ (ns legacy.status-im.node.core (:require - [legacy.status-im.utils.deprecated-types :as types] - [status-im.config :as config])) + [legacy.status-im.utils.deprecated-types :as types])) (defn fleets [{:keys [custom-fleets]}] @@ -9,9 +8,3 @@ (mapv #(:fleets (types/json->clj %)) $) (conj $ custom-fleets) (reduce merge $))) - -(defn current-fleet-key - [db] - (keyword (get-in db - [:profile/profile :fleet] - config/fleet))) diff --git a/src/legacy/status_im/pairing/core.cljs b/src/legacy/status_im/pairing/core.cljs index f3808bf8b2e7..7d2e8d4b7a06 100644 --- a/src/legacy/status_im/pairing/core.cljs +++ b/src/legacy/status_im/pairing/core.cljs @@ -98,7 +98,7 @@ :deviceType utils.platform/os}]})) (rf/defn init - [cofx] + [_cofx] {:pairing/get-our-installations nil}) (rf/defn enable @@ -254,7 +254,7 @@ (rf/defn pair-and-sync {:events [:pairing/pair-and-sync]} - [cofx installation-id] + [_cofx installation-id] {:fx [[:json-rpc/call [{:method "wakuext_enableInstallationAndSync" :params [{:installationId installation-id}] diff --git a/src/legacy/status_im/profile/core.cljs b/src/legacy/status_im/profile/core.cljs index 94b3d238c471..94d228bd83b0 100644 --- a/src/legacy/status_im/profile/core.cljs +++ b/src/legacy/status_im/profile/core.cljs @@ -37,7 +37,7 @@ (rf/defn finish-success {:events [:my-profile/finish-success]} - [{:keys [db] :as cofx}] + [{:keys [db]}] {:db (update db :my-profile/seed assoc :step :finish :error nil :word nil)}) (rf/defn finish diff --git a/src/legacy/status_im/qr_scanner/core.cljs b/src/legacy/status_im/qr_scanner/core.cljs index 9ddf87401c20..040db8e48a77 100644 --- a/src/legacy/status_im/qr_scanner/core.cljs +++ b/src/legacy/status_im/qr_scanner/core.cljs @@ -23,7 +23,7 @@ (rf/defn set-qr-code {:events [:qr-scanner.callback/scan-qr-code-success]} - [{:keys [db]} opts data] + [_ opts data] (when-let [handler (:handler opts)] {:dispatch [handler data opts]})) @@ -46,7 +46,7 @@ (= (:public-key profile) public-key)) (rf/defn handle-private-chat - [{:keys [db] :as cofx} {:keys [chat-id]}] + [{:keys [db]} {:keys [chat-id]}] (if-not (own-public-key? db chat-id) {:dispatch [:chat.ui/start-chat chat-id]} {:effects.utils/show-popup {:title (i18n/label :t/unable-to-read-this-code) diff --git a/src/legacy/status_im/react_native/resources.cljs b/src/legacy/status_im/react_native/resources.cljs index 111f5be215cd..bd4d7c20abb4 100644 --- a/src/legacy/status_im/react_native/resources.cljs +++ b/src/legacy/status_im/react_native/resources.cljs @@ -1,6 +1,4 @@ -(ns legacy.status-im.react-native.resources - (:require - [legacy.status-im.ui.components.colors :as colors])) +(ns legacy.status-im.react-native.resources) (def ui {:empty-chats-header (js/require "../resources/images/ui/empty-chats-header.png") @@ -52,10 +50,6 @@ :no-contacts (js/require "../resources/images/ui/no-contacts.png") :no-contacts-dark (js/require "../resources/images/ui/no-contacts-dark.png")}) -(defn get-theme-image - [k] - (get ui (when (colors/dark?) (keyword (str (name k) "-dark"))) (get ui k))) - (def loaded-images (atom {})) (defn get-image diff --git a/src/legacy/status_im/stickers/core.cljs b/src/legacy/status_im/stickers/core.cljs index 88282686b618..9224369b6344 100644 --- a/src/legacy/status_im/stickers/core.cljs +++ b/src/legacy/status_im/stickers/core.cljs @@ -2,7 +2,6 @@ (:require [legacy.status-im.utils.utils :as utils] [re-frame.core :as re-frame] - [status-im.common.json-rpc.events :as json-rpc] [status-im.constants :as constants] [utils.ethereum.chain :as chain] [utils.re-frame :as rf])) @@ -23,21 +22,6 @@ :params [(chain/chain-id db) id] :on-success #()}]})) -(re-frame/reg-fx :stickers/load-packs - (fn [chain-id] - (json-rpc/call {:method "stickers_market" - :params [chain-id] - :on-success [:stickers/stickers-market-success]}) - (json-rpc/call {:method "stickers_installed" - :params [] - :on-success [:stickers/stickers-installed-success]}) - (json-rpc/call {:method "stickers_pending" - :params [] - :on-success [:stickers/stickers-pending-success]}) - (json-rpc/call {:method "stickers_recent" - :params [] - :on-success [:stickers/stickers-recent-success]}))) - (rf/defn pending-pack {:events [:stickers/pending-pack]} [{db :db} id] diff --git a/src/legacy/status_im/subs/ens.cljs b/src/legacy/status_im/subs/ens.cljs index 842fd1704d47..23ed8d09fe19 100644 --- a/src/legacy/status_im/subs/ens.cljs +++ b/src/legacy/status_im/subs/ens.cljs @@ -1,64 +1,6 @@ (ns legacy.status-im.subs.ens (:require - [clojure.string :as string] - [legacy.status-im.ens.core :as ens] - [re-frame.core :as re-frame] - [utils.address :as address] - [utils.ethereum.chain :as chain] - [utils.money :as money])) - -(re-frame/reg-sub - :ens/preferred-name - :<- [:profile/profile] - (fn [multiaccount] - (:preferred-name multiaccount))) - -(re-frame/reg-sub - :ens/search-screen - :<- [:ens/registration] - (fn [{:keys [custom-domain? username state]}] - {:state state - :username username - :custom-domain? custom-domain?})) - -(defn- ens-amount-label - [chain-id] - (str (ens/registration-cost chain-id) - (case chain-id - 3 " STT" - 1 " SNT" - ""))) - -(re-frame/reg-sub - :ens/checkout-screen - :<- [:ens/registration] - :<- [:chain-keyword] - :<- [:multiaccount/default-account] - :<- [:multiaccount/public-key] - :<- [:chain-id] - :<- [:wallet-legacy] - (fn [[{:keys [custom-domain? username address]} - chain default-account public-key chain-id wallet]] - (let [address (or address (address/normalized-hex (:address default-account))) - balance (get-in wallet [:accounts address :balance])] - {:address address - :username username - :public-key public-key - :custom-domain? custom-domain? - :chain chain - :amount-label (ens-amount-label chain-id) - :sufficient-funds? (money/sufficient-funds? - (money/formatted->internal (money/bignumber 10) - (chain/chain-keyword->snt-symbol chain) - 18) - (get balance (chain/chain-keyword->snt-symbol chain)))}))) - -(re-frame/reg-sub - :ens/confirmation-screen - :<- [:ens/registration] - (fn [{:keys [username state]}] - {:state state - :username username})) + [re-frame.core :as re-frame])) (re-frame/reg-sub :ens/current-names @@ -66,37 +8,3 @@ :<- [:chain-id] (fn [[all-names chain-id]] (get all-names chain-id))) - -(re-frame/reg-sub - :ens.name/screen - :<- [:get-screen-params :ens-name-details] - :<- [:ens/current-names] - (fn [[name ens]] - (let [{:keys [address public-key expiration-date releasable?]} (get ens name) - pending? (nil? address)] - (cond-> {:name name - :custom-domain? (not (string/ends-with? name ".stateofus.eth"))} - pending? - (assoc :pending? true) - (not pending?) - (assoc :address address - :public-key public-key - :releasable? releasable? - :expiration-date expiration-date))))) - -(re-frame/reg-sub - :ens.main/screen - :<- [:ens/current-names] - :<- [:profile/profile] - :<- [:ens/preferred-name] - :<- [:ens/registrations] - (fn [[names multiaccount preferred-name registrations]] - (let [not-in-progress-names (reduce (fn [acc {:keys [username custom-domain?]}] - (let [full-name (ens/fullname custom-domain? username)] - (remove #(= % full-name) acc))) - (keys names) - (vals registrations))] - {:names not-in-progress-names - :profile/profile multiaccount - :preferred-name preferred-name - :registrations registrations}))) diff --git a/src/legacy/status_im/subs/mailservers.cljs b/src/legacy/status_im/subs/mailservers.cljs index 68d8f757b907..d9254159f83b 100644 --- a/src/legacy/status_im/subs/mailservers.cljs +++ b/src/legacy/status_im/subs/mailservers.cljs @@ -11,31 +11,6 @@ (fn [[current-mailserver-id current-fleet mailservers]] (get-in mailservers [current-fleet current-mailserver-id :name]))) -(re-frame/reg-sub - :mailserver/connecting? - :<- [:mailserver/state] - (fn [state] - (#{:connecting :added} state))) - -(re-frame/reg-sub - :mailserver/connection-error? - :<- [:mailserver/state] - (fn [state] - (#{:error :disconnected} state))) - -(re-frame/reg-sub - :mailserver/fetching? - :<- [:mailserver/state] - :<- [:mailserver/pending-requests] - :<- [:mailserver/connecting?] - :<- [:mailserver/connection-error?] - :<- [:mailserver/request-error?] - (fn [[state pending-requests connecting? connection-error? request-error?]] - (and pending-requests - (= state :connected) - (pos-int? pending-requests) - (not (or connecting? connection-error? request-error?))))) - (re-frame/reg-sub :mailserver/fleet-mailservers :<- [:fleets/current-fleet] @@ -43,23 +18,6 @@ (fn [[current-fleet mailservers]] (current-fleet mailservers))) -(re-frame/reg-sub - :mailserver.edit/connected? - :<- [:mailserver.edit/mailserver] - :<- [:mailserver/current-id] - (fn [[mailserver current-mailserver-id]] - (= (get-in mailserver [:id :value]) - current-mailserver-id))) - -(re-frame/reg-sub - :mailserver.edit/validation-errors - :<- [:mailserver.edit/mailserver] - (fn [mailserver] - (set (keep - (fn [[k {:keys [error]}]] - (when error k)) - mailserver)))) - (re-frame/reg-sub :mailserver/preferred-id :<- [:profile/profile] diff --git a/src/legacy/status_im/subs/root.cljs b/src/legacy/status_im/subs/root.cljs index 0d825c192012..bb088bfc8988 100644 --- a/src/legacy/status_im/subs/root.cljs +++ b/src/legacy/status_im/subs/root.cljs @@ -3,7 +3,6 @@ legacy.status-im.subs.browser legacy.status-im.subs.ens legacy.status-im.subs.mailservers - legacy.status-im.subs.stickers [re-frame.core :as re-frame])) (defn reg-root-key-sub diff --git a/src/legacy/status_im/subs/stickers.cljs b/src/legacy/status_im/subs/stickers.cljs deleted file mode 100644 index 8790cab7982d..000000000000 --- a/src/legacy/status_im/subs/stickers.cljs +++ /dev/null @@ -1,22 +0,0 @@ -(ns legacy.status-im.subs.stickers - (:require - [re-frame.core :as re-frame] - [status-im.constants :as constants])) - -(re-frame/reg-sub - :stickers/all-packs - :<- [:stickers/packs] - (fn [packs] - (map (fn [{:keys [status] :as pack}] - (-> pack - (assoc :installed (= status constants/sticker-pack-status-installed)) - (assoc :pending (= status constants/sticker-pack-status-pending)) - (assoc :owned (= status constants/sticker-pack-status-owned)))) - (vals packs)))) - -(re-frame/reg-sub - :stickers/get-current-pack - :<- [:get-screen-params] - :<- [:stickers/all-packs] - (fn [[{:keys [id]} packs]] - (first (filter #(= (:id %) id) packs)))) diff --git a/src/legacy/status_im/ui/components/accordion.cljs b/src/legacy/status_im/ui/components/accordion.cljs deleted file mode 100644 index 4aee7c9e189e..000000000000 --- a/src/legacy/status_im/ui/components/accordion.cljs +++ /dev/null @@ -1,56 +0,0 @@ -(ns legacy.status-im.ui.components.accordion - (:require - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.icons.icons :as icons] - [legacy.status-im.ui.components.list.item :as list.item] - [legacy.status-im.ui.components.react :as react] - [reagent.core :as reagent])) - -(defn drop-down-icon - [{:keys [opened? dropdown-margin-left]}] - [react/view {:flex-direction :row :align-items :center} - [icons/icon (if opened? :main-icons/dropdown-up :main-icons/dropdown) - {:container-style {:align-items :center - :margin-left dropdown-margin-left - :justify-content :center} - :resize-mode :center - :color colors/black}]]) - -(defn section - "Render collapsible section" - [_props] - (let [opened? (reagent/atom (get _props :default))] - (fn - [{:keys [title content icon opened disabled - padding-vertical dropdown-margin-left - open-container-style - on-open on-close] - :or {padding-vertical 8 - dropdown-margin-left 8 - open-container-style {} - on-open #() - on-close #()}}] - (let [on-press #(do - (apply (if @opened? on-close on-open) []) - (swap! opened? not))] - [react/view - (merge {:padding-vertical padding-vertical} - (when @opened? open-container-style)) - (if (string? title) - [list.item/list-item - {:title title - :icon icon - :on-press on-press - :accessory [drop-down-icon (or @opened? opened)]}] - [react/touchable-opacity {:on-press on-press :disabled disabled} - [react/view - {:flex-direction :row - :margin-right 14 - :justify-content :space-between} - title - [drop-down-icon - {:opened? (or @opened? opened) - :dropdown-margin-left dropdown-margin-left}]]]) - (when (or @opened? opened) - content)])))) - diff --git a/src/legacy/status_im/ui/components/action_sheet.cljs b/src/legacy/status_im/ui/components/action_sheet.cljs index 76ae3c33131d..9e792750cd42 100644 --- a/src/legacy/status_im/ui/components/action_sheet.cljs +++ b/src/legacy/status_im/ui/components/action_sheet.cljs @@ -1,7 +1,7 @@ (ns legacy.status-im.ui.components.action-sheet (:require ["react-native" :refer (ActionSheetIOS)] - [legacy.status-im.utils.core :as utils] + [utils.collection :as utils] [utils.i18n :as i18n])) (defn- callback diff --git a/src/legacy/status_im/ui/components/animated_header.cljs b/src/legacy/status_im/ui/components/animated_header.cljs deleted file mode 100644 index b8f74f55b35a..000000000000 --- a/src/legacy/status_im/ui/components/animated_header.cljs +++ /dev/null @@ -1,69 +0,0 @@ -(ns legacy.status-im.ui.components.animated-header - (:require - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.header :as header] - [oops.core :refer [oget]] - [react-native.core :as rn] - [react-native.platform :as platform] - [react-native.safe-area :as safe-area] - [reagent.core :as reagent])) - -(defn header-wrapper-style - [{:keys [offset]}] - (merge - {:background-color (:ui-background @colors/theme)} - (when (and offset platform/ios?) - {:z-index 2 - :shadow-radius 16 - :shadow-color (:shadow-01 @colors/theme) - :shadow-offset {:width 0 :height 4}}))) - -(defn title-style - [layout] - {:flex 1 - :justify-content :center - :padding-right (get-in layout [:right :width])}) - -(defn header-container - [] - (let [layout (reagent/atom {}) - offset (reagent/atom 0) - on-layout (fn [evt] - (reset! offset (oget evt "nativeEvent" "layout" "height")))] - (fn [{:keys [extended-header refresh-control refreshing-sub refreshing-counter] :as props} children] - [rn/view - {:flex 1 - :pointer-events :box-none} - [rn/view - {:pointer-events :box-none - :style (header-wrapper-style {:offset @offset})} - [header/header - (merge - {:get-layout (fn [el l] (swap! layout assoc el l)) - :border-bottom false - :title-align :left} - (dissoc props :extended-header))]] - (into [rn/scroll-view - {:refreshControl (when refresh-control - (refresh-control - (and @refreshing-sub - @refreshing-counter))) - :style {:z-index 1} - :scrollEventThrottle 16} - [rn/view {:pointer-events :box-none} - [rn/view - {:pointer-events :box-none - :on-layout on-layout} - [extended-header - {:offset @offset}]]]] - children)]))) - -(defn header - [{:keys [use-insets] :as props} & children] - (if use-insets - [header-container - (-> props - (dissoc :use-insets) - (assoc :insets (safe-area/get-insets))) - children] - [header-container props children])) diff --git a/src/legacy/status_im/ui/components/animation.cljs b/src/legacy/status_im/ui/components/animation.cljs index 377cf353ae99..264de9bc0715 100644 --- a/src/legacy/status_im/ui/components/animation.cljs +++ b/src/legacy/status_im/ui/components/animation.cljs @@ -35,12 +35,6 @@ anim-value (clj->js (add-native-driver config)))) -(defn decay - [anim-value config] - (.decay ^js react/animated - anim-value - (clj->js (add-native-driver config)))) - (defn anim-sequence [animations] (.sequence ^js react/animated (clj->js animations))) @@ -49,65 +43,13 @@ [animations] (.parallel ^js react/animated (clj->js animations))) -(defn anim-delay - [duration] - (.delay ^js react/animated duration)) - -(defn event - [mapping config] - (.event ^js react/animated (clj->js mapping) (clj->js config))) - -(defn add-listener - [^js anim-value listener] - (.addListener anim-value listener)) - -(defn remove-all-listeners - [^js anim-value] - (.removeAllListeners anim-value)) - -(defn stop-animation - [^js anim-value] - (.stopAnimation anim-value)) - -(defn set-value - [^js anim-value value] - (.setValue anim-value value)) - -(def animated (.-Animated ^js rn)) (def animated-value (-> ^js rn .-Animated .-Value)) -(def animated-value-xy (-> ^js rn .-Animated .-ValueXY)) (def easing (-> ^js rn .-Easing)) (defn create-value [value] (new animated-value value)) -(defn create-value-xy - [value] - (new animated-value-xy value)) - -(defn add - [anim-x anim-y] - ((-> ^js rn .-Animated .add) anim-x anim-y)) - -(defn subtract - [anim-x anim-y] - ((-> ^js rn .-Animated .-subtract) anim-x anim-y)) - -(defn x - [^js value-xy] - (.-x value-xy)) - -(defn y - [^js value-xy] - (.-y value-xy)) - -(defn get-layout - [^js value-xy] - (js->clj (.getLayout value-xy))) - (defn easing-in [] (.-in ^js easing)) (defn easing-out [] (.-out ^js easing)) -(defn cubic [] (.-cubic ^js easing)) -(def bezier (.-bezier ^js easing)) diff --git a/src/legacy/status_im/ui/components/bottom_panel/views.cljs b/src/legacy/status_im/ui/components/bottom_panel/views.cljs deleted file mode 100644 index 453a6d3b73dd..000000000000 --- a/src/legacy/status_im/ui/components/bottom_panel/views.cljs +++ /dev/null @@ -1,152 +0,0 @@ -(ns legacy.status-im.ui.components.bottom-panel.views - (:require - ["react-native" :refer (BackHandler)] - [legacy.status-im.ui.components.animation :as anim] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.react :as react] - [react-native.platform :as platform] - [reagent.core :as reagent]) - (:require-macros [legacy.status-im.utils.views :as views])) - -(def back-listener (atom nil)) - -(defn remove-back-listener - [] - (when @back-listener - (.remove ^js @back-listener) - (reset! back-listener nil))) - -(defn add-back-listener - [] - (remove-back-listener) - (reset! back-listener (.addEventListener BackHandler - "hardwareBackPress" - (fn [] true)))) - -(defn hide-panel-anim - [bottom-anim-value alpha-value window-height] - (remove-back-listener) - (react/dismiss-keyboard!) - (anim/start - (anim/parallel - [(anim/spring bottom-anim-value - {:toValue (- window-height) - :useNativeDriver true}) - (anim/timing alpha-value - {:toValue 0 - :duration 500 - :useNativeDriver true})]))) - -(defn show-panel-anim - [bottom-anim-value alpha-value] - (add-back-listener) - (anim/start - (anim/parallel - [(anim/spring bottom-anim-value - {:toValue 40 - :useNativeDriver true}) - (anim/timing alpha-value - {:toValue 0.4 - :duration 500 - :useNativeDriver true})]))) - -(defn bottom-panel - [_ render window-height on-close on-touch-outside show-overlay?] - (let [bottom-anim-value (anim/create-value window-height) - alpha-value (anim/create-value 0) - clear-timeout (atom nil) - update? (atom nil) - current-obj (reagent/atom nil)] - (reagent/create-class - {:UNSAFE_componentWillMount (fn [^js args] - (let [[_ obj _ _] (.-argv (.-props args))] - (when @clear-timeout (js/clearTimeout @clear-timeout)) - (when (or (not= obj @current-obj) @update?) - (cond - @update? - (do (reset! update? false) - (show-panel-anim bottom-anim-value alpha-value)) - - (and @current-obj obj) - (do (reset! update? true) - (js/setTimeout #(reset! current-obj obj) 600) - (hide-panel-anim bottom-anim-value - alpha-value - (- window-height))) - - obj - (do (reset! current-obj obj) - (show-panel-anim bottom-anim-value alpha-value)) - - :else - (do (reset! clear-timeout (js/setTimeout #(reset! current-obj - nil) - 600)) - (hide-panel-anim bottom-anim-value - alpha-value - (- window-height))))))) - :UNSAFE_componentWillUpdate (fn [_ [_ obj _ _]] - (when @clear-timeout (js/clearTimeout @clear-timeout)) - (when (or (not= obj @current-obj) @update?) - (cond - @update? - (do (reset! update? false) - (show-panel-anim bottom-anim-value alpha-value)) - - (and @current-obj obj) - (do (reset! update? true) - (js/setTimeout #(reset! current-obj obj) 600) - (hide-panel-anim bottom-anim-value - alpha-value - (- window-height))) - - obj - (do (reset! current-obj obj) - (show-panel-anim bottom-anim-value alpha-value)) - - :else - (do (reset! clear-timeout (js/setTimeout #(reset! current-obj - nil) - 600)) - (hide-panel-anim bottom-anim-value - alpha-value - (- window-height)))))) - :reagent-render (fn [] - (if @current-obj - [react/keyboard-avoiding-view - {:style {:position :absolute :top 0 :bottom 0 :left 0 :right 0} - :ignore-offset true} - - [react/view {:flex 1} - (when (and platform/ios? show-overlay?) - [react/animated-view - {:flex 1 - :background-color colors/black-persist - :opacity alpha-value}]) - (when on-touch-outside - [react/touchable-opacity - {:active-opacity 0 - :on-press on-touch-outside - :style {:flex 1}}]) - [react/animated-view - {:style {:position :absolute - :transform [{:translateY bottom-anim-value}] - :bottom 0 - :left 0 - :right 0}} - [react/view {:flex 1} - [render @current-obj]]]]] - ;;TODO this is not great, improve! - #(do (on-close) - nil)))}))) - -(views/defview animated-bottom-panel - [m view on-close on-touch-outside show-overlay?] - (views/letsubs [{window-height :height} [:dimensions/window]] - [bottom-panel - (when m - (select-keys m - [:from :contact :amount :token :approve? :message :cancel? :hash :name :url :icons - :wc-version :params :connector :description :topic :relay :self :peer :permissions - :state])) view window-height on-close on-touch-outside - (if-not (nil? show-overlay?) show-overlay? true)])) diff --git a/src/legacy/status_im/ui/components/button/view.cljs b/src/legacy/status_im/ui/components/button/view.cljs index 65d49cc4b711..5eebe9f146ec 100644 --- a/src/legacy/status_im/ui/components/button/view.cljs +++ b/src/legacy/status_im/ui/components/button/view.cljs @@ -67,7 +67,6 @@ :else theme) {:keys [icon-color background-color text-color border-color]} (themes theme')] - [rn/touchable-without-feedback (merge {:disabled disabled :accessibility-label accessibility-label} diff --git a/src/legacy/status_im/ui/components/chat_icon/screen.cljs b/src/legacy/status_im/ui/components/chat_icon/screen.cljs index d053164c080d..dabdf4dd127f 100644 --- a/src/legacy/status_im/ui/components/chat_icon/screen.cljs +++ b/src/legacy/status_im/ui/components/chat_icon/screen.cljs @@ -3,7 +3,6 @@ [clojure.string :as string] [legacy.status-im.ui.components.chat-icon.styles :as styles] [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.icons.icons :as icons] [legacy.status-im.ui.screens.chat.photos :as photos] [legacy.status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils] [quo.components.avatars.user-avatar.style :as user-avatar.style] @@ -12,8 +11,7 @@ [re-frame.core :as re-frame.core] [react-native.core :as rn] [status-im.contexts.profile.utils :as profile.utils] - [utils.ens.core :as utils.ens] - [utils.image-server :as image-server])) + [utils.ens.core :as utils.ens])) ;;TODO REWORK THIS NAMESPACE @@ -37,20 +35,6 @@ [rn/text {:style (:default-chat-icon-text styles)} (get-name-first-char name)]])) -(defn chat-icon-view - [chat-id group-chat name styles] - [rn/view (:container styles) - (if group-chat - [default-chat-icon name styles] - (let [photo-path @(re-frame.core/subscribe [:chats/photo-path chat-id])] - [photos/photo photo-path styles]))]) - -(defn emoji-chat-icon - [emoji styles] - (when-not (string/blank? emoji) - [rn/view (:default-chat-icon styles) - [rn/text {:style (:default-chat-icon-text styles)} emoji]])) - (defn profile-photo-plus-dot-view [{:keys [public-key full-name customization-color photo-container photo-path community?]}] (let [theme @(re-frame.core/subscribe [:theme]) @@ -88,35 +72,6 @@ {:style dot-styles :accessibility-label dot-accessibility-label}])])) -(defn emoji-chat-icon-view - [chat-id group-chat name emoji styles] - [rn/view (:container styles) - (if group-chat - (if (string/blank? emoji) - [default-chat-icon name styles] - [emoji-chat-icon emoji styles]) - [profile-photo-plus-dot-view - {:public-key chat-id - :photo-container (:default-chat-icon styles)}])]) - -(defn chat-icon-view-chat-list - [chat-id group-chat name color] - [chat-icon-view chat-id group-chat name - {:container styles/container-chat-list - :size 40 - :chat-icon styles/chat-icon-chat-list - :default-chat-icon (styles/default-chat-icon-chat-list color) - :default-chat-icon-text (styles/default-chat-icon-text 40)}]) - -(defn chat-icon-view-chat-sheet - [chat-id group-chat name color] - [chat-icon-view chat-id group-chat name - {:container styles/container-chat-list - :size 40 - :chat-icon styles/chat-icon-chat-list - :default-chat-icon (styles/default-chat-icon-chat-list color) - :default-chat-icon-text (styles/default-chat-icon-text 40)}]) - (defn custom-icon-view-list [name color & [size]] [rn/view (styles/container-list-size (or size 40)) @@ -147,44 +102,4 @@ :default-chat-icon (styles/default-chat-icon-profile colors/default-chat-color size) :default-chat-icon-text (styles/default-chat-icon-text size)}]) -(defn profile-icon-view - [photo-path name color emoji edit? size override-styles public-key community?] - (let [styles (merge {:container {:width size :height size} - :size size - :chat-icon styles/chat-icon-profile - :default-chat-icon (styles/default-chat-icon-profile color size) - :default-chat-icon-text (if (string/blank? emoji) - (styles/default-chat-icon-text size) - (styles/emoji-chat-icon-text size))} - override-styles) - img-config (:config photo-path) - photo-path (if img-config - ;; temp support new media server avatar for old component - {:uri (image-server/get-image-uri - img-config - {:size size - :full-name name - :font-size (get-in styles [:default-chat-icon-text :font-size]) - :background-color (get-in styles [:default-chat-icon :background-color]) - :indicator-size 0 - :indicator-border 0 - :indicator-color "#000000" - :color (get-in styles [:default-chat-icon-text :color]) - :length 2 - :ring? (not (utils.ens/is-valid-eth-name? name)) - :ring-width 2})} - photo-path)] - [rn/view (:container styles) - (if (and photo-path (seq photo-path)) - [profile-photo-plus-dot-view - {:photo-path photo-path - :public-key public-key - :photo-container (:container styles) - :community? community?}] - [rn/view {:accessibility-label :chat-icon} - (if (string/blank? emoji) - [default-chat-icon name styles] - [emoji-chat-icon emoji styles])]) - (when edit? - [rn/view {:style (styles/chat-icon-profile-edit)} - [icons/tiny-icon :tiny-icons/tiny-edit {:color colors/white-persist}]])])) + diff --git a/src/legacy/status_im/ui/components/chat_icon/styles.cljs b/src/legacy/status_im/ui/components/chat_icon/styles.cljs index 8e7e2afb1f47..7e93cba42e6c 100644 --- a/src/legacy/status_im/ui/components/chat_icon/styles.cljs +++ b/src/legacy/status_im/ui/components/chat_icon/styles.cljs @@ -1,7 +1,6 @@ (ns legacy.status-im.ui.components.chat-icon.styles (:require - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.emoji-thumbnail.utils :as emoji-utils])) + [legacy.status-im.ui.components.colors :as colors])) (defn default-chat-icon [color] @@ -13,51 +12,6 @@ :border-radius 20 :background-color color}) -(defn default-chat-icon-redesign - [color size] - {:margin 0 - :width size - :height size - :align-items :center - :justify-content :center - :border-radius (/ size 2) - :background-color color}) - -(defn default-chat-icon-chat-list - [color] - (merge (default-chat-icon color) - {:width 40 - :height 40 - :border-radius 20})) - -(defn default-list-chat-icon-redesign - [color size] - (merge (default-chat-icon-redesign color size) - {:width size - :height size - :border-radius (/ size 2)})) - -(defn default-community-icon-chat-list - [color] - (merge (default-chat-icon color) - {:width 48 - :height 48 - :border-radius 48})) - -(defn default-token-icon-chat-list - [color] - (merge (default-chat-icon color) - {:width 20 - :height 20 - :border-radius 20})) - -(defn default-chat-icon-chat-toolbar - [color size] - (merge (default-chat-icon color) - {:width size - :height size - :border-radius size})) - (defn default-chat-icon-profile [color size] (merge (default-chat-icon color) @@ -72,71 +26,12 @@ :font-size (/ size 2) :line-height size}) -(defn emoji-chat-icon-text - [size] - {:font-size (emoji-utils/emoji-font-size size) - :line-height size - :margin-top (emoji-utils/emoji-top-margin-for-vertical-alignment size)}) ;; Required for vertical alignment bug - Check function defination for more info - (def chat-icon {:margin 4 :border-radius 20 :width 40 :height 40}) -(defn chat-icon-redesign - [size] - {:margin 4 - :border-radius (/ size 2) - :width size - :height size}) - -(def chat-icon-chat-list - (merge chat-icon - {:width 40 - :height 40 - :margin 0})) - -(defn community-status-icon - [size] - {:margin 4 - :border-radius 10 - :width size - :height size}) - -(def community-icon-chat-list - (merge chat-icon - {:width 48 - :height 48 - :margin 0})) - -(defn community-icon-chat-list-redesign - [size] - (merge (chat-icon size) - {:width size - :height size - :margin 0})) - -(defn community-status-chat-list-icon - [size] - (merge (community-status-icon size) - {:width size - :height size - :margin 0})) - -(def token-icon-chat-list - (merge chat-icon - {:width 20 - :height 20 - :margin 0})) - -(defn chat-icon-chat-toolbar - [size] - (merge chat-icon - {:width size - :height size - :margin 0})) - (defn custom-size-icon [size] (merge chat-icon @@ -144,44 +39,11 @@ :height size :margin 0})) -(def chat-icon-profile - (merge chat-icon - {:width 64 - :height 64 - :border-radius 32})) - (def container-chat-list {:width 40 :height 40}) -(def token-icon-container-chat-list - {:width 20 - :height 20}) - -(def community-icon-container-chat-list - {:width 48 - :height 48}) - (defn container-list-size [size] {:width size :height size}) - -(defn container-chat-toolbar - [size] - {:width size - :height size}) - -(defn chat-icon-profile-edit - [] - {:width 24 - :height 24 - :border-radius 12 - :border-width 1 - :border-color colors/white-persist - :background-color colors/blue - :justify-content :center - :align-items :center - :position :absolute - :bottom -2 - :right -2}) diff --git a/src/legacy/status_im/ui/components/checkbox/styles.cljs b/src/legacy/status_im/ui/components/checkbox/styles.cljs deleted file mode 100644 index 91495ce0bc18..000000000000 --- a/src/legacy/status_im/ui/components/checkbox/styles.cljs +++ /dev/null @@ -1,15 +0,0 @@ -(ns legacy.status-im.ui.components.checkbox.styles - (:require - [legacy.status-im.ui.components.colors :as colors])) - -(def wrapper - {:width 24 :height 24 :align-items :center :justify-content :center}) - -(defn icon-check-container - [checked?] - {:background-color (if checked? colors/blue colors/gray-lighter) - :align-items :center - :justify-content :center - :border-radius 2 - :width 18 - :height 18}) diff --git a/src/legacy/status_im/ui/components/checkbox/view.cljs b/src/legacy/status_im/ui/components/checkbox/view.cljs deleted file mode 100644 index f1a31dc8d47f..000000000000 --- a/src/legacy/status_im/ui/components/checkbox/view.cljs +++ /dev/null @@ -1,27 +0,0 @@ -(ns legacy.status-im.ui.components.checkbox.view - (:require - [legacy.status-im.ui.components.checkbox.styles :as styles] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.icons.icons :as icons] - [legacy.status-im.ui.components.react :as react])) - -(defn checkbox - "react/check-box is currently not available on iOS, - use it once it is available on all platforms" - [{:keys [on-value-change checked? accessibility-label style] - :or {accessibility-label :checkbox}}] - [(if on-value-change react/touchable-highlight react/view) - (merge {:style (merge - styles/wrapper - style) - :accessibility-label (str accessibility-label - "-" - (if checked? "on" "off"))} - (when on-value-change - {:on-press #(on-value-change (not checked?))})) - (if checked? - [icons/tiny-icon - :tiny-icons/tiny-check - {:container-style (styles/icon-check-container true) - :color colors/white-persist}] - [react/view {:style (styles/icon-check-container false)}])]) diff --git a/src/legacy/status_im/ui/components/colors.cljs b/src/legacy/status_im/ui/components/colors.cljs index c5f5875e262e..374fd638aa6b 100644 --- a/src/legacy/status_im/ui/components/colors.cljs +++ b/src/legacy/status_im/ui/components/colors.cljs @@ -125,16 +125,12 @@ (def white-persist (:ui-background light-theme)) ;; this doesn't with theme (def white-transparent-10 (:interactive-03 light-theme)) ;; Used as icon background color for a dark foreground (def white-transparent (:icon-03 light-theme)) ;; Used as icon color on dark background and input placeholder color -(def white-transparent-persist (:icon-03 light-theme)) (def white-transparent-70 (:text-03 light-theme)) (def white-transparent-70-persist (:text-03 light-theme)) (def mentioned-background (:mentioned-background old-colors-mapping-light)) (def mentioned-border (:mentioned-border old-colors-mapping-light)) -(def red-light "#ffe5ea") ;; error tooltip TODO (andrey) should be white, but shadow - ;; needed - ;; BLACK (def black (:text-01 light-theme)) ;; Used as the default text color (def black-persist (:ui-background dark-theme)) ;; this doesn't with theme @@ -143,10 +139,7 @@ ;; color for containers like "Backup recovery phrase" (def black-transparent-20 (:backdrop light-theme)) ; accounts divider (def black-transparent-40 (:backdrop light-theme)) -(def black-transparent-40-persist (:backdrop light-theme)) (def black-transparent-50 (:backdrop light-theme)) -(def black-light "#2d2d2d") ;; sign-with-keycard-button -(def black-transparent-86 (:ui-03 light-theme)) ;; DARK GREY (def gray (:text-02 light-theme)) ;; Dark grey, used as a background for a light foreground and @@ -160,7 +153,7 @@ ;; ACCENT BLUE (def blue (:interactive-01 light-theme)) ;; Accent blue, used as main wallet color, and ios home add ;; button -(def blue-persist (:interactive-01 light-theme)) + ;; LIGHT BLUE (def blue-light (:interactive-02 light-theme)) ;; Light Blue (def blue-transparent-10 (alpha blue 0.1)) ;; unknown @@ -168,7 +161,7 @@ ;; RED (def red (:negative-01 light-theme)) ;; Used to highlight errors or "dangerous" actions (def red-transparent-10 (alpha red 0.1)) ;;action-row ;; ttt finish -(def red-audio-recorder "#fa6565") + ;; GREEN (def green "#44d058") ;; icon for successful inboud transaction @@ -177,32 +170,9 @@ ;; YELLOW (def pin-background (:pin-background old-colors-mapping-light)) ;; Light yellow, used as background for pinned messages -(def purple "#887af9") -(def orange "#FE8F59") - -(def chat-colors - ["#fa6565" - "#7cda00" - purple - "#51d0f0" - orange - "#d37ef4"]) - -(def account-colors - ["#9B832F" - "#D37EF4" - "#1D806F" - "#FA6565" - "#7CDA00" - purple - "#8B3131"]) - -(def mention-incoming "#0DA4C9") -(def mention-outgoing "#9EE8FA") + (def text black) (def text-gray gray) -(def default-community-color "#773377") - (def default-chat-color "#a187d5") ;; legacy ;; THEME diff --git a/src/legacy/status_im/ui/components/common/common.cljs b/src/legacy/status_im/ui/components/common/common.cljs index 88dc21646a27..be1be60925d3 100644 --- a/src/legacy/status_im/ui/components/common/common.cljs +++ b/src/legacy/status_im/ui/components/common/common.cljs @@ -1,28 +1,10 @@ (ns legacy.status-im.ui.components.common.common (:require [legacy.status-im.ui.components.common.styles :as styles] - [legacy.status-im.ui.components.icons.icons :as icons] [legacy.status-im.ui.components.react :as react] - [reagent.core :as reagent] - [utils.i18n :as i18n]) + [reagent.core :as reagent]) (:require-macros [legacy.status-im.utils.views :refer [defview letsubs]])) -(defn logo - [{:keys [size]}] - [icons/icon :icons/logo (styles/logo size)]) - -;;TODO DEPRECATED, use legacy.status-im.ui.components.badge -(defn counter - ([value] (counter nil value)) - ([{:keys [size accessibility-label] :or {size 18}} value] - (let [more-than-9 (> value 9)] - [react/view {:style (styles/counter-container size)} - [react/text - (cond-> {:style (styles/counter-label size)} - accessibility-label - (assoc :accessibility-label accessibility-label)) - (if more-than-9 (i18n/label :t/counter-9-plus) value)]]))) - (def small-screen-image-k 0.8) (def small-screen-height 600) diff --git a/src/legacy/status_im/ui/components/common/styles.cljs b/src/legacy/status_im/ui/components/common/styles.cljs index 95a5f787a3cd..d6052db7df12 100644 --- a/src/legacy/status_im/ui/components/common/styles.cljs +++ b/src/legacy/status_im/ui/components/common/styles.cljs @@ -11,29 +11,6 @@ :align-items :center :justify-content :center}) -(defn logo - [icon-size] - {:width icon-size - :height icon-size - :color :none - :container-style {}}) - -(defn counter-container - [size] - {:width size - :height size - :border-radius (/ size 2) - :background-color colors/blue - :align-items :center - :justify-content :center}) - -(defn counter-label - [size] - {:font-size (inc (/ size 2)) - :typography :main-medium - :color colors/white-persist - :text-align :center}) - (def image-contain {:align-self :stretch :align-items :center diff --git a/src/legacy/status_im/ui/components/copyable_text.cljs b/src/legacy/status_im/ui/components/copyable_text.cljs deleted file mode 100644 index c6cd8bc3b3c1..000000000000 --- a/src/legacy/status_im/ui/components/copyable_text.cljs +++ /dev/null @@ -1,129 +0,0 @@ -(ns legacy.status-im.ui.components.copyable-text - (:require - [legacy.status-im.ui.components.animation :as animation] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.react :as react] - [reagent.core :as reagent] - [utils.i18n :as i18n])) - -(defn hide-cue-atom - [anim-opacity anim-y cue-atom] - (animation/start - (animation/parallel - [(animation/timing - anim-opacity - {:toValue 0 - :duration 140 - :delay 1000 - :easing (.-ease ^js animation/easing) - :useNativeDriver true}) - (animation/timing - anim-y - {:toValue 0 - :duration 140 - :delay 1000 - :easing (.-ease ^js animation/easing) - :useNativeDriver true})]) - #(reset! cue-atom false))) - -(defn show-cue-atom - [anim-opacity anim-y cue-atom y] - (when @cue-atom - (animation/start - (animation/parallel - [(animation/timing - anim-opacity - {:toValue 1 - :duration 140 - :easing (.-ease ^js animation/easing) - :useNativeDriver true}) - (animation/timing - anim-y - {:toValue y - :duration 140 - :easing (.-ease ^js animation/easing) - :useNativeDriver true})]) - #(hide-cue-atom anim-opacity anim-y cue-atom)))) - -(defn copy-action-visual-cue - [anim-opacity anim-y width cue-atom] - [react/animated-view - {:style - {:opacity anim-opacity - :transform [{:translateY anim-y}] - :max-width @width - :z-index (if @cue-atom 1 -1) - :height 34 - :position :absolute - :border-radius 8 - :align-self :center - :align-items :center - :justify-content :center - :shadow-offset {:width 0 :height 4} - :shadow-radius 12 - :elevation 8 - :shadow-opacity 1 - :shadow-color "rgba(0, 34, 51, 0.08)" - :background-color colors/white}} - [react/view - {:padding-horizontal 16 - :padding-vertical 7 - :border-radius 8 - :background-color colors/white - :shadow-offset {:width 0 :height 2} - :shadow-radius 4 - :shadow-opacity 1 - :shadow-color "rgba(0, 34, 51, 0.16)"} - [react/text - {:style - {:typography :main-medium - ;; line height specified here because of figma spec - :line-height 20 - :font-size 14}} - (i18n/label :t/sharing-copied-to-clipboard)]]]) - -(defn copyable-text-view - [{:keys [label container-style]} content] - (let [cue-atom (reagent/atom false) - background-color (or (get container-style :background-color) colors/white) - width (reagent/atom 0) - height (reagent/atom 0) - anim-y (animation/create-value 0) - anim-opacity (animation/create-value 0)] - (reagent/create-class - {:reagent-render - (fn [{:keys [copied-text]} _] - (let [copy-fn #(when (not @cue-atom) - (reset! cue-atom true) - (show-cue-atom - anim-opacity - anim-y - cue-atom - (if (> @height 34) - (- (/ @height 2)) - (- (+ 17 @height)))) - (react/copy-to-clipboard copied-text))] - [react/view - {:style (if container-style container-style {}) - :on-layout - #(do - (reset! width (-> ^js % .-nativeEvent .-layout .-width)) - (reset! height (-> ^js % .-nativeEvent .-layout .-height)))} - (when label - [react/text - {:style - {:font-size 13 - ;; line height specified here because of figma spec - :line-height 18 - :font-weight "500" - :color colors/gray - :margin-bottom 4}} - (i18n/label label)]) - [copy-action-visual-cue anim-opacity anim-y width cue-atom] - [react/touchable-highlight - {:active-opacity (if @cue-atom 1 0.85) - :underlay-color colors/black - :on-press copy-fn - :on-long-press copy-fn} - [react/view {:background-color background-color} - content]]]))}))) diff --git a/src/legacy/status_im/ui/components/core.cljs b/src/legacy/status_im/ui/components/core.cljs index 3e914580f092..a8fa3a41c58f 100644 --- a/src/legacy/status_im/ui/components/core.cljs +++ b/src/legacy/status_im/ui/components/core.cljs @@ -1,10 +1,8 @@ (ns legacy.status-im.ui.components.core (:require - [legacy.status-im.ui.components.animated-header :as animated-header] [legacy.status-im.ui.components.button.view :as button] [legacy.status-im.ui.components.controls.view :as controls] [legacy.status-im.ui.components.header :as header] - [legacy.status-im.ui.components.list.footer :as list-footer] [legacy.status-im.ui.components.list.header :as list-header] [legacy.status-im.ui.components.separator :as separator] [legacy.status-im.ui.components.text :as text] @@ -12,11 +10,8 @@ (def text text/text) (def header header/header) -(def animated-header animated-header/header) (def text-input text-input/text-input) (def button button/button) (def list-header list-header/header) -(def list-footer list-footer/footer) - (def radio controls/radio) (def separator separator/separator) diff --git a/src/legacy/status_im/ui/components/emoji_thumbnail/color_picker.cljs b/src/legacy/status_im/ui/components/emoji_thumbnail/color_picker.cljs deleted file mode 100644 index 53577c6d16b3..000000000000 --- a/src/legacy/status_im/ui/components/emoji_thumbnail/color_picker.cljs +++ /dev/null @@ -1,52 +0,0 @@ -(ns legacy.status-im.ui.components.emoji-thumbnail.color-picker - (:require - [legacy.status-im.ui.components.emoji-thumbnail.styles :as styles] - [react-native.core :as rn])) - -(def emoji-picker-colors-row1 - [{:name "red" :color "#F5A3A3" :key "1"} - {:name "pink" :color "#F5A3BF" :key "2"} - {:name "magenta" :color "#E9A3F5" :key "3"} - {:name "purple" :color "#C0A3F5" :key "4"} - {:name "indigo" :color "#A3B0F5" :key "5"} - {:name "blue" :color "#A3C2F5" :key "6"} - {:name "cyan" :color "#A3DCF5" :key "7"}]) - -(def emoji-picker-colors-row2 - [{:name "teal" :color "#A3ECF5" :key "8"} - {:name "mint" :color "#A3F5E2" :key "9"} - {:name "green" :color "#A3F5BA" :key "10"} - {:name "moss" :color "#CFF5A3" :key "11"} - {:name "lemon" :color "#EEF5A3" :key "12"} - {:name "yellow" :color "#F5F5A3" :key "13"}]) - -(def emoji-picker-colors-row3 - [{:name "honey" :color "#F5E4A3" :key "14"} - {:name "orange" :color "#F5D7A3" :key "15"} - {:name "peach" :color "#F5B6A3" :key "16"} - {:name "brown" :color "#E0C2B8" :key "17"} - {:name "grey" :color "#CCCCCC" :key "18"} - {:name "dove" :color "#DAE2E7" :key "19"} - {:name "white" :color "#FFFFFF" :key "20"}]) - -(defn colors-row - [color-circle container-style colors] - [rn/view {:style container-style :accessibility-label :colors-row} - (for [x colors] - [color-circle x])]) - -(defn color-picker-section - [color-circle] - [:<> - [colors-row ;; Row - 1st - color-circle - (merge styles/emoji-picker-color-row-container styles/emoji-picker-row1-style) - emoji-picker-colors-row1] - [colors-row ;; Row - 2nd - color-circle - (merge styles/emoji-picker-color-row-container styles/emoji-picker-row2-style) - emoji-picker-colors-row2] - [colors-row ;; Row - 3rd - color-circle - (merge styles/emoji-picker-color-row-container styles/emoji-picker-row3-style) - emoji-picker-colors-row3]]) diff --git a/src/legacy/status_im/ui/components/emoji_thumbnail/preview.cljs b/src/legacy/status_im/ui/components/emoji_thumbnail/preview.cljs deleted file mode 100644 index f424d87ee796..000000000000 --- a/src/legacy/status_im/ui/components/emoji_thumbnail/preview.cljs +++ /dev/null @@ -1,19 +0,0 @@ -(ns legacy.status-im.ui.components.emoji-thumbnail.preview - (:require - [clojure.string :as string] - [legacy.status-im.ui.components.emoji-thumbnail.styles :as styles] - [legacy.status-im.ui.components.react :as react])) - -(defn emoji-thumbnail - [emoji color size] - (when-not (string/blank? emoji) - [react/view (styles/emoji-thumbnail-icon color size) - [react/text - {:style (styles/emoji-thumbnail-icon-text size) - :accessibility-label :thumbnail-emoji} emoji]])) - -(defn emoji-thumbnail-touchable - [emoji color size func] - (when-not (string/blank? emoji) - [react/touchable-opacity {:on-press func} - [emoji-thumbnail emoji color size]])) diff --git a/src/legacy/status_im/ui/components/emoji_thumbnail/styles.cljs b/src/legacy/status_im/ui/components/emoji_thumbnail/styles.cljs deleted file mode 100644 index 5449c02cc846..000000000000 --- a/src/legacy/status_im/ui/components/emoji_thumbnail/styles.cljs +++ /dev/null @@ -1,171 +0,0 @@ -(ns legacy.status-im.ui.components.emoji-thumbnail.styles - (:require - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.emoji-thumbnail.utils :as emoji-utils] - [react-native.platform :as platform])) - -(defn emoji-thumbnail-icon - [color size] - {:width size - :height size - :align-items :center - :justify-content :center - :border-radius (/ size 2) - :background-color color - :border-width 0.5 - :border-color "rgba(0,0,0,0.1)" - :accessibility-label :thumbnail-container-circle}) - -(defn emoji-thumbnail-icon-text - [size] - {:font-size (emoji-utils/emoji-font-size size) - :line-height size - :margin-top (emoji-utils/emoji-top-margin-for-vertical-alignment size)}) ;; Required for vertical alignment bug - Check function defination for more info - - -;; Styles Related to Emoji Thumbnail Picker - -(def emoji-thumbnail-preview-size 60) - -(def emoji-picker-upper-components-size - (if platform/android? 350 405)) - -(defn emoji-picker-gray-color - [] - (if (colors/dark?) "#c3c3bc99" "#3C3C4399")) - -(defn emoji-picker-category-container - [] - (if (colors/dark?) "#110d0a" "#EEF2F5")) - -(defn emoji-picker-active-category-container - [] - (if (colors/dark?) "#87877f33" "#78788033")) - -(defn emoji-picker-active-category-color - [] - (if (colors/dark?) "#bbbbbb" "#000000")) - -(def emoji-thumbnail-preview - {:margin-top 16 - :margin-bottom 16 - :align-items :center - :justify-content :center - :accessibility-label :emoji-preview}) - -(defn emoji-picker-keyboard-container - [] - {:border-radius 0 - :background-color (colors/get-color :ui-background)}) - -(defn emoji-picker-search-bar - [] - {:border-radius 10 - :height 36 - :background-color (:ui-01 @colors/theme)}) - -(defn emoji-picker-search-bar-text - [] - {:color (emoji-picker-gray-color)}) - -(defn emoji-picker-header - [] - {:font-size 13 - :color (emoji-picker-gray-color) - :font-weight "600" - :margin-top 7 - :margin-bottom 0}) - -(defn emoji-keyboard - [func] - {:onEmojiSelected func - :emojiSize 23 - :containerStyles (emoji-picker-keyboard-container) - :categoryPosition "floating" - :categoryContainerColor (emoji-picker-category-container) - :activeCategoryColor (emoji-picker-active-category-color) - :activeCategoryContainerColor (emoji-picker-active-category-container) - :categoryColor (emoji-picker-gray-color) - :enableSearchBar true - :searchBarTextStyles (emoji-picker-search-bar-text) - :searchBarStyles (emoji-picker-search-bar) - :searchBarPlaceholderColor (emoji-picker-gray-color) - :closeSearchColor (emoji-picker-gray-color) - :headerStyles (emoji-picker-header) - :disabledCategory ["symbols"]}) - -(def emoji-picker-color-row-container - {:flex-direction "row" - :justify-content "space-around" - :flex-grow 1}) - -(def emoji-picker-row1-style - {:margin-top 10}) - -(def emoji-picker-row2-style - {:margin-top 10 - :margin-bottom 10 - :margin-left 25 - :margin-right 25}) - -(def emoji-picker-row3-style - {:margin-bottom 10}) - -(defn emoji-picker-color-border - [item_color color-selected?] - {:height 44 - :width 44 - :border-radius 22 - :border-width 2 - :border-color (if color-selected? item_color "#00000000") - :align-items :center - :justify-content :center}) - -(defn emoji-picker-color - [item_color] - {:height 36 - :width 36 - :border-radius 18 - :border-width 0.5 - :background-color item_color - :border-color "rgba(0,0,0,0.1)"}) - -(def emoji-picker-default-thumbnails - [{:emoji "🐺" :color "#CCCCCC"} - {:emoji "🏆" :color "#F5E4A3"} - {:emoji "🦀" :color "#F5A3A3"} - {:emoji "🍁" :color "#F5D7A3"} - {:emoji "🐳" :color "#A3DCF5"} - {:emoji "🦕" :color "#CFF5A3"} - {:emoji "🐥" :color "#F5F5A3"} - {:emoji "🐇" :color "#DAE2E7"} - {:emoji "🐒" :color "#E0C2B8"} - {:emoji "🦍" :color "#CCCCCC"} - {:emoji "🤠" :color "#E0C2B8"} - {:emoji "👾" :color "#F5A3BF"} - {:emoji "🕴️" :color "#CCCCCC"} - {:emoji "💃" :color "#F5A3A3"} - {:emoji "🦹" :color "#E9A3F5"} - {:emoji "🐕" :color "#F5D7A3"} - {:emoji "🦇" :color "#C0A3F5"} - {:emoji "🦜" :color "#F5A3A3"} - {:emoji "🐢" :color "#CFF5A3"} - {:emoji "🦎" :color "#CFF5A3"} - {:emoji "🐊" :color "#CFF5A3"} - {:emoji "🦋" :color "#F5B6A3"} - {:emoji "🕸️" :color "#CCCCCC"} - {:emoji "🦈" :color "#A3DCF5"} - {:emoji "☘️" :color "#CFF5A3"} - {:emoji "🍇" :color "#E9A3F5"} - {:emoji "🍎" :color "#F5B6A3"} - {:emoji "🥥" :color "#E0C2B8"} - {:emoji "🧀" :color "#F5E4A3"} - {:emoji "🥪" :color "#F5D7A3"} - {:emoji "🥣" :color "#A3DCF5"} - {:emoji "🍜" :color "#F5B6A3"} - {:emoji "🧁" :color "#A3DCF5"} - {:emoji "☕" :color "#DAE2E7"} - {:emoji "🍷" :color "#F5A3A3"} - {:emoji "🚆" :color "#A3DCF5"} - {:emoji "👓" :color "#CCCCCC"} - {:emoji "🎶" :color "#A3DCF5"}]) diff --git a/src/legacy/status_im/ui/components/emoji_thumbnail/utils.cljs b/src/legacy/status_im/ui/components/emoji_thumbnail/utils.cljs deleted file mode 100644 index 57ef46d6b1e7..000000000000 --- a/src/legacy/status_im/ui/components/emoji_thumbnail/utils.cljs +++ /dev/null @@ -1,16 +0,0 @@ -(ns legacy.status-im.ui.components.emoji-thumbnail.utils - (:require - [react-native.platform :as platform])) - -(defn emoji-font-size - [container_size] - (int (* (/ container_size 10) 6))) - -;; React Native Bug: Till version 0.65 React Native has a bug. It doesn't center text/emoji -;; inside the container(In Android & Web Only). Even with the textAlign: "center" and other properties. -;; So this top margin is required so that emoji will center in the emoji circle. -;; More Info: https://github.com/facebook/react-native/issues/32198 -;; TODO: Remove this top margin, if future updates of react-native fix this issue. -(defn emoji-top-margin-for-vertical-alignment - [container_size] - (if platform/android? (- (int (/ container_size 20))) 0)) diff --git a/src/legacy/status_im/ui/components/invite/views.cljs b/src/legacy/status_im/ui/components/invite/views.cljs deleted file mode 100644 index c52fea895594..000000000000 --- a/src/legacy/status_im/ui/components/invite/views.cljs +++ /dev/null @@ -1,30 +0,0 @@ -(ns legacy.status-im.ui.components.invite.views - (:require - [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.list.item :as list.item] - [re-frame.core :as re-frame] - [utils.i18n :as i18n])) - -(defn button - [] - [quo/button - {:on-press #(re-frame/dispatch [:invite.events/share-link nil]) - :accessibility-label :invite-friends-button} - (i18n/label :t/invite-friends)]) - -(defn list-item - [{:keys [accessibility-label]}] - [list.item/list-item - {:theme :accent - :title (i18n/label :t/invite-friends) - :icon :main-icons/share - :accessibility-label accessibility-label - :on-press (fn [] - (re-frame/dispatch [:bottom-sheet/hide-old]) - (js/setTimeout - #(re-frame/dispatch [:invite.events/share-link nil]) - 250))}]) - - - - diff --git a/src/legacy/status_im/ui/components/keyboard_avoid_presentation.cljs b/src/legacy/status_im/ui/components/keyboard_avoid_presentation.cljs deleted file mode 100644 index e3e4a8bb8e81..000000000000 --- a/src/legacy/status_im/ui/components/keyboard_avoid_presentation.cljs +++ /dev/null @@ -1,17 +0,0 @@ -(ns legacy.status-im.ui.components.keyboard-avoid-presentation - (:require - [legacy.status-im.ui.components.react :as react] - [react-native.utils :as rn.utils] - [reagent.core :as reagent])) - -(defn keyboard-avoiding-view - [& argv] - (let [[props children] (rn.utils/get-props-and-children argv)] - (reagent/as-element - (into [react/keyboard-avoiding-view - (update props - :keyboard-vertical-offset - + - 20 - (if (:ignore-offset props) 44 0))] - children)))) diff --git a/src/legacy/status_im/ui/components/list/footer.cljs b/src/legacy/status_im/ui/components/list/footer.cljs deleted file mode 100644 index 844758d6ecbf..000000000000 --- a/src/legacy/status_im/ui/components/list/footer.cljs +++ /dev/null @@ -1,18 +0,0 @@ -(ns legacy.status-im.ui.components.list.footer - (:require - [legacy.status-im.ui.components.spacing :as spacing] - [legacy.status-im.ui.components.text :as text] - [react-native.core :as rn] - [react-native.utils :as rn.utils])) - -(defn footer - [& argv] - (let [[props children] (rn.utils/get-props-and-children argv) - {:keys [color] - :or {color :secondary}} - props] - [rn/view - {:style (merge (:base spacing/padding-horizontal) - (:small spacing/padding-vertical))} - (into [text/text {:color color}] - children)])) diff --git a/src/legacy/status_im/ui/components/list/styles.cljs b/src/legacy/status_im/ui/components/list/styles.cljs index edef95b639e3..edcccd7fe0fc 100644 --- a/src/legacy/status_im/ui/components/list/styles.cljs +++ b/src/legacy/status_im/ui/components/list/styles.cljs @@ -3,47 +3,6 @@ [legacy.status-im.ui.components.colors :as colors] [legacy.status-im.utils.styles :as styles])) -(def item - {:flex-direction :row - :justify-content :center - :padding-horizontal 16}) - -(def item-content-view - {:flex 1 - :flex-direction :column - :justify-content :center}) - -(def item-checkbox - {:flex 1 - :flex-direction :column - :align-items :center - :justify-content :center}) - -(def icon-size 24) -(def icon-wrapper-size (+ icon-size (* 2 8))) - -(def item-icon-wrapper - {:width icon-wrapper-size - :height icon-wrapper-size - :align-items :center - :justify-content :center}) - -(def item-icon - {:width icon-size - :height icon-size}) - -(def left-item-wrapper - {:justify-content :center - :margin-vertical 12}) - -(def content-item-wrapper - {:flex 1 - :justify-content :center - :margin-horizontal 16}) - -(def right-item-wrapper - {:justify-content :center}) - (def base-separator {:height 1 :background-color colors/black-transparent}) diff --git a/src/legacy/status_im/ui/components/profile_header/view.cljs b/src/legacy/status_im/ui/components/profile_header/view.cljs deleted file mode 100644 index 5a24a2dd9376..000000000000 --- a/src/legacy/status_im/ui/components/profile_header/view.cljs +++ /dev/null @@ -1,110 +0,0 @@ -(ns legacy.status-im.ui.components.profile-header.view - (:require - [legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.icons.icons :as icons] - [legacy.status-im.ui.components.spacing :as spacing] - [react-native.core :as rn] - [react-native.reanimated :as animated])) - -(def avatar-extended-size 64) -(def avatar-minimized-size 40) -(def subtitle-margin 4) - -(defn container-style - [{:keys [animation minimized]}] - (merge {:flex-direction :row - :padding-vertical 4 - :align-items :center} - (if-not minimized - (:base spacing/padding-horizontal) - {:opacity animation}))) - -(defn header-bottom-separator - [] - {:margin-bottom (:tiny spacing/spacing) - :height (:small spacing/spacing) - :border-bottom-width 1 - :border-bottom-color (:ui-01 @colors/theme)}) - -(defn header-text - [] - {:padding-left (:base spacing/spacing) - :flex 1 - :justify-content :center}) - -(defn header-subtitle - [{:keys [minimized]}] - (merge {:padding-right (:large spacing/spacing) - :flex-direction :row - :align-items :center} - (when-not minimized - {:padding-top subtitle-margin}))) - -(defn extended-header - [{:keys [title photo color membership subtitle subtitle-icon on-edit on-press monospace - bottom-separator emoji public-key community?] - :or {bottom-separator true}}] - (fn [{:keys [animation minimized]}] - (let [wrapper (if on-press - [rn/touchable-opacity {:on-press on-press}] - [:<>]) - editable (if (and (not minimized) on-edit) - [rn/touchable-opacity {:on-press on-edit}] - [:<>])] - (into - wrapper - [[animated/view {:pointer-events :box-none} - [animated/view - {:style (container-style {:animation animation - :minimized minimized}) - :pointer-events :box-none} - (into editable - [[animated/view {:pointer-events :box-none} - [chat-icon.screen/profile-icon-view - photo title color emoji (and (not minimized) on-edit) - (if minimized avatar-minimized-size avatar-extended-size) - nil public-key community?]]]) - [animated/view - {:style (header-text) - :pointer-events :box-none} - [quo/text - {:animated? true - :number-of-lines (if minimized 1 2) - :size (if minimized :base :x-large) - :weight :bold - :elipsize-mode :tail - :accessibility-role :text - :accessibility-label :default-username} - title] - (when membership - [quo/text - {:number-of-lines 1 - :ellipsize-mode :middle - :monospace monospace - :size (if minimized :small :base) - :color :secondary} - membership]) - (when subtitle - [animated/view - {:style (header-subtitle {:minimized minimized}) - :pointer-events :box-none} - (when subtitle-icon - [icons/icon subtitle-icon - {:color (:icon-02 @colors/theme) - :width 16 - :height 16 - :container-style {:margin-right 4}}]) - [quo/text - {:number-of-lines 1 - :ellipsize-mode :middle - :monospace monospace - :size (if minimized :small :base) - :color :secondary} - subtitle]])]] - (when-not minimized - [animated/view - {:pointer-events :none - :style (when bottom-separator (header-bottom-separator))}])]])))) - diff --git a/src/legacy/status_im/ui/components/react.cljs b/src/legacy/status_im/ui/components/react.cljs index ce9abf362c3d..6027922d6722 100644 --- a/src/legacy/status_im/ui/components/react.cljs +++ b/src/legacy/status_im/ui/components/react.cljs @@ -2,26 +2,19 @@ (:require ["@react-native-clipboard/clipboard" :default Clipboard] ["@react-native-community/blur" :as blur] - ["@react-native-community/masked-view" :default MaskedView] ["react" :as reactjs] - ["react-native" :as react-native :refer (Keyboard BackHandler)] + ["react-native" :as react-native :refer (Keyboard)] ["react-native-fast-image" :as FastImage] - ["react-native-image-crop-picker" :default image-picker] - ["react-native-linear-gradient" :default LinearGradient] ["react-native-navigation" :refer (Navigation)] [legacy.status-im.ui.components.colors :as colors] [legacy.status-im.ui.components.text-style :as typography] - [legacy.status-im.utils.utils :as utils] [react-native.platform :as platform] [reagent.core :as reagent] - [utils.i18n :as i18n]) - (:require-macros [legacy.status-im.utils.views :as views])) + [utils.i18n :as i18n])) -(def native-modules (.-NativeModules react-native)) ;; React Components -(def app-state (.-AppState react-native)) (def view (reagent/adapt-react-class (.-View react-native))) (def scroll-view-class (reagent/adapt-react-class (.-ScrollView react-native))) @@ -34,15 +27,6 @@ (def fast-image-class (reagent/adapt-react-class FastImage)) -(defn image-get-size [uri callback] (.getSize (.-Image react-native) uri callback)) -(defn resolve-asset-source - [uri] - (js->clj (.resolveAssetSource (.-Image react-native) uri) :keywordize-keys true)) - -(def linear-gradient (reagent/adapt-react-class LinearGradient)) - -(def masked-view (reagent/adapt-react-class MaskedView)) - (def blur-view (reagent/adapt-react-class (.-BlurView blur))) (defn valid-source? @@ -64,23 +48,12 @@ [switch-class props]) (def touchable-highlight-class (reagent/adapt-react-class (.-TouchableHighlight react-native))) -(def pressable-class (reagent/adapt-react-class (.-Pressable react-native))) -(def touchable-without-feedback-class - (reagent/adapt-react-class (.-TouchableWithoutFeedback react-native))) -(def touchable-opacity-class (reagent/adapt-react-class (.-TouchableOpacity react-native))) (def activity-indicator-class (reagent/adapt-react-class (.-ActivityIndicator react-native))) (defn activity-indicator [props] [activity-indicator-class (update props :color #(or % colors/gray))]) -(defn small-loading-indicator - [color] - [activity-indicator - {:color color - :ios {:size :small} - :android {:size :16}}]) - (def animated (.-Animated react-native)) (def animated-view-class @@ -89,19 +62,11 @@ (def animated-flat-list-class (reagent/adapt-react-class (.-FlatList ^js animated))) -(def animated-scroll-view-class - (reagent/adapt-react-class (.-ScrollView ^js animated))) - (defn animated-view [props & content] (vec (conj content props animated-view-class))) -(defn animated-scroll-view - [props & children] - (vec (conj children props animated-scroll-view-class))) - (def dimensions (.-Dimensions react-native)) -(def keyboard (.-Keyboard react-native)) (def dismiss-keyboard! #(.dismiss ^js Keyboard)) (def linking (.-Linking react-native)) @@ -190,61 +155,16 @@ [{style :style k :key}] [text {:style style} (i18n/label k)]) -(defn touchable-opacity - [props content] - [touchable-opacity-class props content]) - (defn touchable-highlight [props content] [touchable-highlight-class (merge {:underlay-color :transparent} props) content]) -(defn pressable - [props content] - [pressable-class props content]) - -(defn touchable-without-feedback - [props content] - [touchable-without-feedback-class - props - content]) - (defn get-dimensions [name] (js->clj (.get ^js dimensions name) :keywordize-keys true)) -;; Image picker -(defn show-access-error - [o] - (when (= "E_PERMISSION_MISSING" (.-code ^js o)) - (utils/show-popup (i18n/label :t/error) - (i18n/label :t/photos-access-error)))) - -(defn show-image-picker - ([images-fn] - (show-image-picker images-fn nil nil)) - ([images-fn - {:keys [media-type] - :or {media-type "any"} - :as props} - finally-callback] - (-> ^js image-picker - (.openPicker (clj->js (merge {:mediaType media-type} - props))) - (.then images-fn) - (.catch show-access-error) - (.finally finally-callback)))) - -(defn show-image-picker-camera - ([images-fn] - (show-image-picker-camera images-fn nil nil)) - ([images-fn props finally-callback] - (-> ^js image-picker - (.openCamera (clj->js props)) - (.then images-fn) - (.catch show-access-error) - (.finally finally-callback)))) ;; Clipboard @@ -255,10 +175,7 @@ [s] (.setString ^js Clipboard s)) -(defn get-from-clipboard - [clbk] - (let [clipboard-contents (.getString ^js Clipboard)] - (.then clipboard-contents #(clbk %)))) + ;; KeyboardAvoidingView (def navigation-const (atom nil)) @@ -278,42 +195,6 @@ (update props :keyboard-vertical-offset + 44 (:status-bar-height @navigation-const))))] children)) -(defn keyboard-avoiding-view-new - [props & children] - (into [keyboard-avoiding-view-class - (merge (when platform/ios? {:behavior :padding}) - (if (:ignore-offset props) - props - (update props :keyboard-vertical-offset + 44)))] - children)) - (defn scroll-view [props & children] (vec (conj children props scroll-view-class))) - -(views/defview with-activity-indicator - [{:keys [timeout style enabled? preview]} component] - (views/letsubs - [loading (reagent/atom true)] - {:component-did-mount (fn [] - (if (or (nil? timeout) - (> 100 timeout)) - (reset! loading false) - (utils/set-timeout #(reset! loading false) - timeout)))} - (if (and (not enabled?) @loading) - (or preview - [view - {:style (or style - {:justify-content :center - :align-items :center})} - [activity-indicator {:animating true}]]) - component))) - -(defn hw-back-add-listener - [callback] - (.addEventListener BackHandler "hardwareBackPress" callback)) - -(defn hw-back-remove-listener - [callback] - (.removeEventListener BackHandler "hardwareBackPress" callback)) diff --git a/src/legacy/status_im/ui/components/search_input/view.cljs b/src/legacy/status_im/ui/components/search_input/view.cljs deleted file mode 100644 index 86b7e06c171d..000000000000 --- a/src/legacy/status_im/ui/components/search_input/view.cljs +++ /dev/null @@ -1,45 +0,0 @@ -(ns legacy.status-im.ui.components.search-input.view - (:require - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.core :as quo] - [reagent.core :as reagent] - [utils.i18n :as i18n])) - -(defn search-input-old - [{:keys [search-active?]}] - (let [input-ref (atom nil) - search-active? (or search-active? (reagent/atom nil))] - (fn [{:keys [on-focus on-change on-blur on-cancel search-filter auto-focus]}] - [quo/text-input - {:placeholder (i18n/label :t/search) - :accessibility-label :search-input - :blur-on-submit true - :multiline false - :get-ref #(reset! input-ref %) - :default-value search-filter - :auto-focus auto-focus - :on-cancel on-cancel - :show-cancel true - :auto-correct false - :auto-capitalize :none - :input-style {:height 36 - :padding-top 2 - :padding-bottom 2} - :before {:icon :main-icons/search - :style {:padding-horizontal 8} - :on-press #(some-> ^js @input-ref - (.focus)) - :icon-opts {:color (:icon-02 @colors/theme)}} - :on-focus #(do - (when on-focus - (on-focus search-filter)) - (reset! search-active? true)) - :on-blur #(do - (when on-blur - (on-blur)) - (reset! search-active? false)) - :on-change (fn [e] - (let [^js native-event (.-nativeEvent ^js e) - text (.-text native-event)] - (when on-change - (on-change text))))}]))) diff --git a/src/legacy/status_im/ui/components/slider.cljs b/src/legacy/status_im/ui/components/slider.cljs deleted file mode 100644 index 71fb37f8a917..000000000000 --- a/src/legacy/status_im/ui/components/slider.cljs +++ /dev/null @@ -1,10 +0,0 @@ -(ns legacy.status-im.ui.components.slider - (:require - ["@react-native-community/slider" :default Slider] - ["react-native" :refer (Animated)] - [reagent.core :as reagent])) - -(def slider (reagent/adapt-react-class Slider)) - -(def animated-slider - (reagent/adapt-react-class (.createAnimatedComponent Animated Slider))) diff --git a/src/legacy/status_im/ui/components/tabs.cljs b/src/legacy/status_im/ui/components/tabs.cljs deleted file mode 100644 index fbadd6bc810c..000000000000 --- a/src/legacy/status_im/ui/components/tabs.cljs +++ /dev/null @@ -1,36 +0,0 @@ -(ns legacy.status-im.ui.components.tabs - (:require - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.react :as react])) - -(defn tab-title - [state k label active?] - [react/view {:align-items :center} - [react/touchable-highlight - {:on-press #(swap! state assoc :tab k) - :underlay-color colors/gray-lighter - :accessibility-label (str label "-item-button") - :style {:border-radius 8}} - [react/view {:padding-horizontal 12 :padding-vertical 8} - [react/text - {:style {:font-weight "500" :color (if active? colors/blue colors/gray) :line-height 22}} - label]]] - (when active? - [react/view {:width 24 :height 3 :border-radius 4 :background-color colors/blue}])]) - -(defn tab-button - [state k label active?] - [react/view - {:flex 1 - :align-items :center - :border-radius 8 - :background-color (if active? colors/blue colors/blue-light)} - [react/touchable-highlight - {:on-press #(swap! state assoc :tab k) - :accessibility-label (str label "-item-button") - :style {:border-radius 8} - :flex 1} - [react/view {:padding-horizontal 12 :padding-vertical 8} - [react/text - {:style {:font-weight "500" :color (if active? colors/white colors/blue) :line-height 22}} - label]]]]) diff --git a/src/legacy/status_im/ui/components/text_input.cljs b/src/legacy/status_im/ui/components/text_input.cljs index e47883c64b3d..ff67c2d64218 100644 --- a/src/legacy/status_im/ui/components/text_input.cljs +++ b/src/legacy/status_im/ui/components/text_input.cljs @@ -26,8 +26,6 @@ (s/nilable (s/or :string string? :component vector?))) (s/def ::cancel-label (s/nilable string?)) -(s/def ::default-value (s/nilable string?)) -(s/def ::placeholder (s/nilable string?)) (s/def ::keyboard-type (s/nilable (s/or :string string? :keyword keyword?))) ; TODO: make set diff --git a/src/legacy/status_im/ui/components/toastable_highlight.cljs b/src/legacy/status_im/ui/components/toastable_highlight.cljs deleted file mode 100644 index d28dd1873e76..000000000000 --- a/src/legacy/status_im/ui/components/toastable_highlight.cljs +++ /dev/null @@ -1,121 +0,0 @@ -(ns legacy.status-im.ui.components.toastable-highlight - "A wrapped touchable highlight that presents a toast when clicked" - (:require - [legacy.status-im.ui.components.animation :as animation] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.react :as react] - [reagent.core :as reagent])) - -(defn hide-cue-atom - [anim-opacity anim-y cue-atom] - (animation/start - (animation/parallel - [(animation/timing - anim-opacity - {:toValue 0 - :duration 140 - :delay 1000 - :easing (.-ease ^js animation/easing) - :useNativeDriver true}) - (animation/timing - anim-y - {:toValue 0 - :duration 140 - :delay 1000 - :easing (.-ease ^js animation/easing) - :useNativeDriver true})]) - #(reset! cue-atom false))) - -(defn show-cue-atom - [anim-opacity anim-y cue-atom y] - (when @cue-atom - (animation/start - (animation/parallel - [(animation/timing - anim-opacity - {:toValue 1 - :duration 140 - :easing (.-ease ^js animation/easing) - :useNativeDriver true}) - (animation/timing - anim-y - {:toValue y - :duration 140 - :easing (.-ease ^js animation/easing) - :useNativeDriver true})]) - #(hide-cue-atom anim-opacity anim-y cue-atom)))) - -(defn toast - [anim-opacity anim-y width cue-atom label] - [react/animated-view - {:style - {:opacity anim-opacity - :transform [{:translateY anim-y}] - :max-width @width - :z-index (if @cue-atom 1 -1) - :height 34 - :position :absolute - :border-radius 8 - :align-self :center - :align-items :center - :justify-content :center - :shadow-offset {:width 0 :height 4} - :shadow-radius 12 - :elevation 8 - :shadow-opacity 1 - :shadow-color "rgba(0, 34, 51, 0.08)" - :background-color colors/white}} - [react/view - {:padding-horizontal 16 - :padding-vertical 7 - :border-radius 8 - :background-color colors/white - :shadow-offset {:width 0 :height 2} - :shadow-radius 4 - :shadow-opacity 1 - :shadow-color "rgba(0, 34, 51, 0.16)"} - [react/text - {:style - {:typography :main-medium - ;; line height specified here because of figma spec - :line-height 20 - :font-size 14}} - label]]]) - -(defn toastable-highlight-view - [{:keys [toast-label on-press - container-style]} - content] - (let [cue-atom (reagent/atom false) - width (reagent/atom 0) - height (reagent/atom 0) - anim-y (animation/create-value 0) - anim-opacity (animation/create-value 0)] - (reagent/create-class - {:reagent-render - (fn [{:keys []} _] - (let [press-fn #(when (not @cue-atom) - (reset! cue-atom true) - (show-cue-atom - anim-opacity - anim-y - cue-atom - (if (> @height 34) - (- (/ @height 2)) - (- (+ 17 @height)))) - (when on-press - (on-press)))] - [react/view - {:style (if container-style container-style {}) - :on-layout - #(do - (reset! width (-> ^js % .-nativeEvent .-layout .-width)) - (reset! height (-> ^js % .-nativeEvent .-layout .-height)))} - [toast anim-opacity anim-y width cue-atom toast-label] - [react/touchable-highlight - {:active-opacity (if @cue-atom 1 0.85) - :underlay-color colors/black - :on-press press-fn - :on-long-press press-fn} - [react/view {:background-color colors/white} - content]]]))}))) diff --git a/src/legacy/status_im/ui/components/tooltip/styles.cljs b/src/legacy/status_im/ui/components/tooltip/styles.cljs index 0974a54c8a98..cf5c783c70f0 100644 --- a/src/legacy/status_im/ui/components/tooltip/styles.cljs +++ b/src/legacy/status_im/ui/components/tooltip/styles.cljs @@ -4,17 +4,6 @@ [legacy.status-im.utils.styles :as styles] [status-im.config :as config])) -(def tooltip-container - (merge - {:position :absolute - :align-items :center - :left 0 - :right 0 - :top 0} - ;;we need this for e2e tests - (when-not config/tooltip-events? - {:pointer-events :none}))) - (styles/def bottom-tooltip-container {:position :absolute :align-items :center @@ -38,20 +27,6 @@ (assoc :margin-top -20 :position :relative))) -(defn tooltip-text-container - [color] - {:padding-horizontal 16 - :padding-vertical 6 - :elevation 3 - :background-color color - :border-radius 8 - :shadow-radius 12 - :shadow-offset {:width 0 :height 4} - :shadow-opacity 0.16 - :shadow-color (if (colors/dark?) - "rgba(0, 0, 0, 0.75)" - "rgba(0, 34, 51)")}) - (def bottom-tooltip-text-container {:flex-direction :row :align-items :center @@ -61,12 +36,6 @@ :background-color colors/gray :border-radius 8}) -(defn tooltip-text - [font-size] - {:color colors/red - :line-height 15 - :font-size font-size}) - (def bottom-tooltip-text {:color colors/white}) diff --git a/src/legacy/status_im/ui/components/tooltip/views.cljs b/src/legacy/status_im/ui/components/tooltip/views.cljs index 36a0fbcd8013..9f3dea8f2995 100644 --- a/src/legacy/status_im/ui/components/tooltip/views.cljs +++ b/src/legacy/status_im/ui/components/tooltip/views.cljs @@ -8,28 +8,6 @@ [legacy.status-im.ui.components.tooltip.styles :as styles]) (:require-macros [legacy.status-im.utils.views :as views])) -(views/defview tooltip - [label & - [{:keys [bottom-value color font-size container-style] - :or {bottom-value 30 color colors/white font-size 15}} - accessibility-label]] - (views/letsubs [bottom-anim-value (animation/create-value bottom-value) - opacity-value (animation/create-value 0)] - {:component-did-mount (animations/animate-tooltip bottom-value bottom-anim-value opacity-value -10)} - [react/view (merge styles/tooltip-container container-style) - [react/animated-view {:style (styles/tooltip-animated bottom-anim-value opacity-value)} - (when label - [react/view (styles/tooltip-text-container color) - [react/text - {:style (styles/tooltip-text font-size) - :accessibility-label accessibility-label} - label]]) - #_[icons/icon :icons/tooltip-tip - (assoc - styles/tooltip-triangle - :color - color)]]])) - (views/defview bottom-tooltip-info [label on-close] (views/letsubs [bottom-anim-value (animation/create-value 75) diff --git a/src/legacy/status_im/ui/screens/advanced_settings/views.cljs b/src/legacy/status_im/ui/screens/advanced_settings/views.cljs index e6ae1b5e5f20..e5e883734d4a 100644 --- a/src/legacy/status_im/ui/screens/advanced_settings/views.cljs +++ b/src/legacy/status_im/ui/screens/advanced_settings/views.cljs @@ -9,11 +9,6 @@ [utils.re-frame :as rf]) (:require-macros [legacy.status-im.utils.views :as views])) -(defn hide-sheet-and-dispatch - [event] - (re-frame/dispatch [:bottom-sheet/hide-old]) - (re-frame/dispatch event)) - (defn- normal-mode-settings-data [{:keys [current-log-level light-client-enabled? diff --git a/src/legacy/status_im/ui/screens/browser/bookmarks/views.cljs b/src/legacy/status_im/ui/screens/browser/bookmarks/views.cljs deleted file mode 100644 index 4e5fa3b52a96..000000000000 --- a/src/legacy/status_im/ui/screens/browser/bookmarks/views.cljs +++ /dev/null @@ -1,55 +0,0 @@ -(ns legacy.status-im.ui.screens.browser.bookmarks.views - (:require - [clojure.string :as string] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.keyboard-avoid-presentation :as kb-presentation] - [legacy.status-im.ui.components.react :as react] - [legacy.status-im.ui.components.toolbar :as toolbar] - [legacy.status-im.ui.components.topbar :as topbar] - [re-frame.core :as re-frame] - [reagent.core :as reagent] - [utils.i18n :as i18n])) - -(defn screen - [{url :url name :name new-arg :new}] - (let [input-name (reagent/atom name)] - (fn [] - (let [edit? (not new-arg)] - [kb-presentation/keyboard-avoiding-view - {:style {:flex 1} - :ignore-offset true} - [topbar/topbar - {:modal? true - :border-bottom true - :title (if edit? (i18n/label :t/edit-favourite) (i18n/label :t/new-favourite))}] - [react/view {:flex 1} - [quo/text-input - {:container-style {:margin 16 :margin-top 10} - :accessibility-label :bookmark-input - :max-length 100 - :auto-focus true - :show-cancel false - :label (i18n/label :t/name) - :default-value @input-name - :on-change-text #(reset! input-name %)}] - [react/text {:style {:margin 16 :color colors/gray}} - url]] - [toolbar/toolbar - {:show-border? true - :center - [quo/button - {:accessibility-label :save-bookmark - :type :secondary - :disabled (string/blank? @input-name) - :on-press #(do (if edit? - (re-frame/dispatch [:browser/update-bookmark - {:url url :name @input-name}]) - (re-frame/dispatch [:browser/store-bookmark - {:url url :name @input-name}])) - (re-frame/dispatch [:navigate-back]))} - (if edit? (i18n/label :t/save) (i18n/label :t/add-favourite))]}]])))) - -(defn new-bookmark - [] - [screen @(re-frame/subscribe [:get-screen-params])]) diff --git a/src/legacy/status_im/ui/screens/browser/eip3085/sheet.cljs b/src/legacy/status_im/ui/screens/browser/eip3085/sheet.cljs deleted file mode 100644 index 0b7dcf06470e..000000000000 --- a/src/legacy/status_im/ui/screens/browser/eip3085/sheet.cljs +++ /dev/null @@ -1,57 +0,0 @@ -(ns legacy.status-im.ui.screens.browser.eip3085.sheet - (:require - [legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.icons.icons :as icons] - [legacy.status-im.ui.components.react :as react] - [legacy.status-im.ui.screens.browser.styles :as styles] - [re-frame.core :as re-frame] - [utils.i18n :as i18n]) - (:require-macros [legacy.status-im.utils.views :as views])) - -(views/defview permissions-panel - [_dapp-name message-id params] - (views/letsubs [{:keys [dapp? dapp]} [:get-current-browser]] - [react/view {} - [react/view styles/permissions-panel-icons-container - (if dapp? - [chat-icon.screen/dapp-icon-permission dapp 40] - [react/view styles/permissions-panel-dapp-icon-container - [icons/icon :main-icons/dapp {:color colors/gray}]]) - [react/view {:margin-left 8 :margin-right 4} - [react/view styles/dot]] - [react/view {:margin-right 4} - [react/view styles/dot]] - [react/view {:margin-right 8} - [react/view styles/dot]] - [react/view styles/permissions-panel-ok-icon-container - [icons/icon :tiny-icons/tiny-check styles/permissions-panel-ok-ico]] - [react/view {:margin-left 8 :margin-right 4} - [react/view styles/dot]] - [react/view {:margin-right 4} - [react/view styles/dot]] - [react/view {:margin-right 8} - [react/view styles/dot]] - [react/view styles/permissions-panel-wallet-icon-container - [icons/icon :main-icons/wallet {:color colors/white}]]] - [react/view - {:style {:flex-direction :row - :justify-content :center - :margin-horizontal 8 - :margin-top 24}} - [react/view - {:flex 1 - :margin-horizontal 8} - [quo/button - {:theme :negative - :on-press #(re-frame/dispatch [:eip3085.ui/dapp-permission-denied message-id params])} - (i18n/label :t/deny)]] - [react/view - {:flex 1 - :margin-horizontal 8} - [quo/button - {:theme :positive - :style {:margin-horizontal 8} - :on-press #(re-frame/dispatch [:eip3085.ui/dapp-permission-allowed message-id params])} - (i18n/label :t/allow)]]]])) diff --git a/src/legacy/status_im/ui/screens/browser/eip3326/sheet.cljs b/src/legacy/status_im/ui/screens/browser/eip3326/sheet.cljs deleted file mode 100644 index cc2623757370..000000000000 --- a/src/legacy/status_im/ui/screens/browser/eip3326/sheet.cljs +++ /dev/null @@ -1,68 +0,0 @@ -(ns legacy.status-im.ui.screens.browser.eip3326.sheet - (:require - [legacy.status-im.network.core :as network] - [legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.icons.icons :as icons] - [legacy.status-im.ui.components.react :as react] - [legacy.status-im.ui.screens.browser.styles :as styles] - [re-frame.core :as re-frame] - [utils.debounce :as debounce] - [utils.i18n :as i18n]) - (:require-macros [legacy.status-im.utils.views :as views])) - -(views/defview permissions-panel - [dapp-name message-id {:keys [network-from network-to target-network-id] :as params}] - (views/letsubs [{:keys [dapp? dapp]} [:get-current-browser]] - [react/view {} - [react/view styles/permissions-panel-icons-container - (if dapp? - [chat-icon.screen/dapp-icon-permission dapp 40] - [react/view styles/permissions-panel-dapp-icon-container - [icons/icon :main-icons/dapp {:color colors/gray}]]) - [react/view {:margin-left 8 :margin-right 4} - [react/view styles/dot]] - [react/view {:margin-right 4} - [react/view styles/dot]] - [react/view {:margin-right 8} - [react/view styles/dot]] - [react/view styles/permissions-panel-ok-icon-container - [icons/icon :tiny-icons/tiny-check styles/permissions-panel-ok-ico]] - [react/view {:margin-left 8 :margin-right 4} - [react/view styles/dot]] - [react/view {:margin-right 4} - [react/view styles/dot]] - [react/view {:margin-right 8} - [react/view styles/dot]] - [react/view styles/permissions-panel-wallet-icon-container - [icons/icon :main-icons/wallet {:color colors/white}]]] - [react/text {:style styles/permissions-panel-title-label :number-of-lines 2} - (str "\"" dapp-name "\" Allow this site to switch the network?")] - [react/text {:style styles/permissions-panel-description-label :number-of-lines 5} - (str "This will switch the selected network within Status to a previously added network:\n" - network-from - " -> " - network-to - "\nit will require login/logout")] - [react/view - {:style {:flex-direction :row - :justify-content :center - :margin-horizontal 8 - :margin-top 24}} - [react/view - {:flex 1 - :margin-horizontal 8} - [quo/button - {:theme :negative - :on-press #(re-frame/dispatch [:eip3326.ui/dapp-permission-denied message-id params])} - (i18n/label :t/deny)]] - [react/view - {:flex 1 - :margin-horizontal 8} - [quo/button - {:theme :positive - :style {:margin-horizontal 8} - :on-press #(debounce/throttle-and-dispatch [::network/connect-network-pressed target-network-id] - 1000)} - (i18n/label :t/allow)]]]])) diff --git a/src/legacy/status_im/ui/screens/browser/empty_tab/styles.cljs b/src/legacy/status_im/ui/screens/browser/empty_tab/styles.cljs index 21fe3aac46c8..b5399cfbcba0 100644 --- a/src/legacy/status_im/ui/screens/browser/empty_tab/styles.cljs +++ b/src/legacy/status_im/ui/screens/browser/empty_tab/styles.cljs @@ -10,15 +10,6 @@ {:margin-horizontal 16 :margin-vertical 10}) -(defn browser-icon-container - [] - {:width 40 - :height 40 - :border-radius 20 - :background-color colors/gray-lighter - :align-items :center - :justify-content :center}) - (defn dapp-store-container [] {:margin 16 @@ -35,20 +26,3 @@ :font-size 15 :font-weight "500" :line-height 22}) - -(defn dapps-account - [color] - {:flex-direction :row - :background-color color - :border-radius 36 - :padding-horizontal 8 - :padding-vertical 6 - :align-items :center - :justify-content :center - :shadow-offset {:width 0 :height 1} - :shadow-radius 6 - :shadow-opacity 1 - :shadow-color (if (colors/dark?) - "rgba(0, 0, 0, 0.75)" - "rgba(0, 12, 63, 0.2)") - :elevation 2}) diff --git a/src/legacy/status_im/ui/screens/browser/empty_tab/views.cljs b/src/legacy/status_im/ui/screens/browser/empty_tab/views.cljs index 421c7b05a79b..059fd9ed68fa 100644 --- a/src/legacy/status_im/ui/screens/browser/empty_tab/views.cljs +++ b/src/legacy/status_im/ui/screens/browser/empty_tab/views.cljs @@ -8,7 +8,6 @@ [legacy.status-im.ui.components.list.item :as list.item] [legacy.status-im.ui.components.list.views :as list] [legacy.status-im.ui.components.react :as react] - [legacy.status-im.ui.screens.browser.accounts :as accounts] [legacy.status-im.ui.screens.browser.empty-tab.styles :as styles] [legacy.status-im.ui.screens.browser.views :as browser] [re-frame.core :as re-frame] @@ -95,35 +94,6 @@ [react/text {:style {:line-height 22 :font-size 15 :color colors/gray}} (i18n/label :t/favourites)]])]) -(views/defview select-account - [] - (views/letsubs [accounts [:accounts-without-watch-only] - {:keys [name color] :as dapps-account} [:dapps-account]] - [react/view - {:position :absolute - :z-index 2 - :align-items :center - :bottom 16 - :left 0 - :right 0 - :padding-horizontal 32} - [quo/button - {:accessibility-label :select-account - :type :scale - :on-press #(re-frame/dispatch [:show-bottom-sheet - {:content (accounts/accounts-list accounts - dapps-account)}])} - [react/view (styles/dapps-account color) - [icons/icon :main-icons/account {:color colors/white-persist}] - [react/view {:flex-shrink 1} - [react/text - {:numberOfLines 1 - :style {:margin-horizontal 6 - :color colors/white-persist - :typography :main-medium}} - name]] - [icons/icon :main-icons/dropdown {:color colors/white-transparent-persist}]]]])) - (views/defview empty-tab [] (views/letsubs [bookmarks [:bookmarks/active] diff --git a/src/legacy/status_im/ui/screens/browser/options/views.cljs b/src/legacy/status_im/ui/screens/browser/options/views.cljs index 2f8028a6e38e..ef100da677e6 100644 --- a/src/legacy/status_im/ui/screens/browser/options/views.cljs +++ b/src/legacy/status_im/ui/screens/browser/options/views.cljs @@ -2,13 +2,10 @@ (:require [legacy.status-im.browser.core :as browser] [legacy.status-im.qr-scanner.core :as qr-scanner] - [legacy.status-im.ui.components.chat-icon.screen :as chat-icon] [legacy.status-im.ui.components.colors :as colors] [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.icons.icons :as icons] [legacy.status-im.ui.components.list.item :as list.item] [legacy.status-im.ui.components.react :as react] - [legacy.status-im.utils.utils :as utils] [re-frame.core :as re-frame] [utils.i18n :as i18n])) @@ -17,26 +14,6 @@ (re-frame/dispatch [:bottom-sheet/hide-old]) (re-frame/dispatch event)) -(defn wallet-connection - [host account] - (fn [] - [react/view {:flex 1} - [react/text {:style {:align-self :center :margin-horizontal 16 :margin-vertical 8}} - (str "“" host "” " (i18n/label :t/has-permissions))] - [list.item/list-item - {:icon [chat-icon/custom-icon-view-list (:name account) (:color account)] - :title (:name account) - :subtitle (utils/get-shortened-checksum-address (:address account)) - :accessory [icons/icon :main-icons/check {:color colors/gray}]}] - [react/view {:padding-vertical 8} - [react/view {:style {:height 1 :background-color (colors/alpha colors/black 0.1)}}]] - [list.item/list-item - {:theme :negative - :title (i18n/label :t/revoke-access) - :accessibility-label :revoke-access - :icon :main-icons/cancel - :on-press #(hide-sheet-and-dispatch [:browser/revoke-dapp-permissions host])}]])) - (defn browser-options [url _account empty-tab name] (fn [] diff --git a/src/legacy/status_im/ui/screens/chat/message/legacy_style.cljs b/src/legacy/status_im/ui/screens/chat/message/legacy_style.cljs index 012fa121ea67..7d8788796091 100644 --- a/src/legacy/status_im/ui/screens/chat/message/legacy_style.cljs +++ b/src/legacy/status_im/ui/screens/chat/message/legacy_style.cljs @@ -6,10 +6,6 @@ [quo.foundations.typography :as typography] [status-im.constants :as constants])) -(defn style-message-text - [] - {:color colors/text}) - (defn message-wrapper [{:keys [in-popover?]}] (if (not in-popover?) @@ -17,25 +13,6 @@ :padding-right 5} {:margin-right 10})) -(defn emoji-message - [{:keys [incoming-group]}] - {:font-size 28 - :line-height 34 ;TODO: Smaller crops the icon on the top - :margin-right 0 ;; Margin to display outgoing message status - :margin-top (if incoming-group 4 0)}) - -(defn message-view - [{:keys [content-type]}] - (merge - {:border-radius 10} - (when (= content-type constants/content-type-emoji) - {:flex-direction :row}))) - -(defn message-view-content - [] - {:padding-bottom 6 - :overflow :hidden}) - (def status-container {:padding-horizontal 5}) @@ -201,34 +178,3 @@ :border-bottom-right-radius 10 :border-color colors/gray-lighter}) -(defn contact-request-status-label - [state] - {:width 136 - :border-radius 8 - :flex 1 - :justify-content :center - :align-items :center - :background-color (when (= :retry state) - colors/blue-light) - :border-width 1 - :border-color (condp = state - constants/contact-request-message-state-accepted colors/green-transparent-10 - constants/contact-request-message-state-declined colors/red-light - constants/contact-request-message-state-pending colors/gray-lighter - nil) - :padding-vertical 10 - :padding-horizontal 16}) - -(defn content-type-contact-request - [] - {:width 168 - :min-height 224.71 - :border-radius 8 - :border-width 1 - :border-color colors/gray-lighter - :align-items :center - :padding-bottom 10 - :margin-vertical 4 - :align-self :flex-start - :margin-right 0 - :margin-left 8}) diff --git a/src/legacy/status_im/ui/screens/chat/message/legacy_view.cljs b/src/legacy/status_im/ui/screens/chat/message/legacy_view.cljs index 69bcac00f66e..f77e3371f02d 100644 --- a/src/legacy/status_im/ui/screens/chat/message/legacy_view.cljs +++ b/src/legacy/status_im/ui/screens/chat/message/legacy_view.cljs @@ -1,6 +1,5 @@ (ns legacy.status-im.ui.screens.chat.message.legacy-view (:require - [legacy.status-im.react-native.resources :as resources] [legacy.status-im.ui.components.colors :as quo.colors] [legacy.status-im.ui.screens.chat.message.legacy-style :as style] [quo.core :as quo] @@ -154,64 +153,8 @@ [rn/text {:style (style/status-text)}] (-> content :parsed-text peek :children))]])) -(defn contact-request-status-pending - [] - [rn/view {:style {:flex-direction :row}} - [quo/text - {:style {:margin-right 5.27} - :weight :medium - :color :secondary} - (i18n/label :t/contact-request-pending)] - [rn/activity-indicator - {:animating true - :size :small - :color quo.colors/gray}]]) - -(defn contact-request-status-accepted - [] - [quo/text - {:style {:color quo.colors/green} - :weight :medium} - (i18n/label :t/contact-request-accepted)]) - -(defn contact-request-status-declined - [] - [quo/text - {:style {:color quo.colors/red} - :weight :medium} - (i18n/label :t/contact-request-declined)]) - -(defn contact-request-status-label - [state] - [rn/view {:style (style/contact-request-status-label state)} - (condp = state - constants/contact-request-message-state-pending [contact-request-status-pending] - constants/contact-request-message-state-accepted [contact-request-status-accepted] - constants/contact-request-message-state-declined [contact-request-status-declined] - nil)]) - ;;;; SYSTEM -;; CONTACT REQUEST (like system message ? ) no wrapper -(defn system-contact-request - [message _] - [rn/view {:style (style/content-type-contact-request)} - [rn/image - {:source (resources/get-image :hand-wave) - :style {:width 112 - :height 97}}] - [quo/text - {:style {:margin-top 6} - :weight :bold - :size :heading-2} - (i18n/label :t/contact-request)] - [rn/view {:style {:padding-horizontal 16}} - [quo/text - {:style {:margin-top 2 - :margin-bottom 14}} - (get-in message [:content :text])]] - [contact-request-status-label (:contact-request-state message)]]) - (defview community-content [{:keys [community-id] :as message}] (letsubs [{:keys [name description verified] :as community} [:communities/community community-id]] diff --git a/src/legacy/status_im/ui/screens/chat/utils.cljs b/src/legacy/status_im/ui/screens/chat/utils.cljs deleted file mode 100644 index 5ccce8a7b899..000000000000 --- a/src/legacy/status_im/ui/screens/chat/utils.cljs +++ /dev/null @@ -1,30 +0,0 @@ -(ns legacy.status-im.ui.screens.chat.utils - (:require - [clojure.string :as string] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.react :as react] - [utils.i18n :as i18n])) - -(defn format-author-old - ([contact] (format-author-old contact nil)) - ([{:keys [primary-name secondary-name nickname]} {:keys [modal profile? you?]}] - (if (not (string/blank? secondary-name)) - [react/nested-text - {:number-of-lines 2 - :style {:color (if modal colors/white-persist colors/blue) - :font-size (if profile? 15 13) - :line-height (if profile? 22 18) - :font-weight "500"}} - (subs primary-name 0 81) - (when you? - [{:style {:color colors/gray :font-weight "400" :font-size 13}} - (str " " (i18n/label :t/You))]) - (when nickname - [{:style {:color colors/gray :font-weight "400"}} - (str " " (subs secondary-name 0 81))])] - [react/text - {:style {:color (if modal colors/white-persist colors/gray) - :font-size (if profile? 15 12) - :line-height (if profile? 22 18) - :font-weight "400"}} - primary-name]))) diff --git a/src/legacy/status_im/ui/screens/communities/invite.cljs b/src/legacy/status_im/ui/screens/communities/invite.cljs deleted file mode 100644 index 7090df5a7908..000000000000 --- a/src/legacy/status_im/ui/screens/communities/invite.cljs +++ /dev/null @@ -1,104 +0,0 @@ -(ns legacy.status-im.ui.screens.communities.invite - (:require - [clojure.string :as string] - [legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen] - [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.list.item :as list.item] - [legacy.status-im.ui.components.toolbar :as toolbar] - [legacy.status-im.ui.components.topbar :as topbar] - [quo.theme] - [react-native.core :as rn] - [reagent.core :as reagent] - [status-im.constants :as constants] - [utils.i18n :as i18n] - [utils.re-frame :as rf])) - -(defn header - [user-pk] - [:<> - [rn/view - {:style {:padding-horizontal 16 - :padding-vertical 8}} - [quo/text-input - {:label (i18n/label :t/enter-user-pk) - :placeholder (i18n/label :t/enter-user-pk) - :on-change-text #(reset! user-pk %) - :default-value @user-pk - :auto-focus true}]] - [quo/separator {:style {:margin-vertical 8}}] - [quo/list-header (i18n/label :t/contacts)]]) - -(defn contacts-list-item - [{:keys [public-key active] :as contact} _ _ {:keys [selected]}] - (let [{:keys [primary-name secondary-name]} contact] - [list.item/list-item - {:title primary-name - :subtitle secondary-name - :icon [chat-icon.screen/contact-icon-contacts-tab contact] - :accessory :checkbox - :active active - :on-press (fn [] - (if active - (swap! selected disj public-key) - (swap! selected conj public-key)))}])) - -(defn legacy-invite - [] - (let [user-pk (reagent/atom "") - contacts-selected (reagent/atom #{}) - {:keys [invite?]} (rf/sub [:get-screen-params])] - (fn [] - (let [theme (quo.theme/use-theme) - contacts-data (rf/sub [:contacts/active]) - {community-id :id - :keys [permissions - can-manage-users?]} - (rf/sub [:communities/edited-community]) - selected @contacts-selected - selected-contacts-count (count selected) - contacts (map (fn [{:keys [public-key] :as contact}] - (assoc contact :active (contains? selected public-key))) - contacts-data) - ;; no-membership communities can only be shared - can-invite? (and can-manage-users? - invite? - (not= (:access permissions) constants/community-no-membership-access)) - on-press-share-community (rn/use-callback - (fn [] - (rf/dispatch [:communities/share-community-confirmation-pressed - selected community-id]) - (rf/dispatch [:navigate-back]) - (rf/dispatch [:toasts/upsert - {:type :positive - :theme theme - :text (if (= 1 selected-contacts-count) - (i18n/label :t/one-user-was-invited) - (i18n/label - :t/n-users-were-invited - {:count selected-contacts-count}))}])) - [community-id selected selected-contacts-count theme])] - [:<> - [topbar/topbar - {:title (i18n/label (if can-invite? - :t/invite-people - :t/community-share-title)) - :modal? true}] - [rn/flat-list - {:style {:flex 1} - :content-container-style {:padding-vertical 16} - ;:header [header user-pk] - :render-data {:selected contacts-selected} - :render-fn contacts-list-item - :key-fn (fn [{:keys [active public-key]}] - (str public-key active)) - :data contacts}] - [toolbar/toolbar - {:show-border? true - :center - [quo/button - {:disabled (and (string/blank? @user-pk) - (zero? selected-contacts-count)) - :accessibility-label :share-community-link - :type :secondary - :on-press on-press-share-community} - (i18n/label (if can-invite? :t/invite :t/share))]}]])))) diff --git a/src/legacy/status_im/ui/screens/fleet_settings/styles.cljs b/src/legacy/status_im/ui/screens/fleet_settings/styles.cljs index 4ed58afb4567..1cac42f0d4db 100644 --- a/src/legacy/status_im/ui/screens/fleet_settings/styles.cljs +++ b/src/legacy/status_im/ui/screens/fleet_settings/styles.cljs @@ -3,9 +3,6 @@ [legacy.status-im.ui.components.colors :as colors] [legacy.status-im.utils.styles :as styles])) -(def wrapper - {:flex 1}) - (def fleet-item-inner {:padding-horizontal 16}) diff --git a/src/legacy/status_im/ui/screens/log_level_settings/styles.cljs b/src/legacy/status_im/ui/screens/log_level_settings/styles.cljs index 867214bb6c81..b774307e13da 100644 --- a/src/legacy/status_im/ui/screens/log_level_settings/styles.cljs +++ b/src/legacy/status_im/ui/screens/log_level_settings/styles.cljs @@ -3,9 +3,6 @@ [legacy.status-im.ui.components.colors :as colors] [legacy.status-im.utils.styles :as styles])) -(def wrapper - {:flex 1}) - (def log-level-item-inner {:padding-horizontal 16}) diff --git a/src/legacy/status_im/ui/screens/notifications_settings/events.cljs b/src/legacy/status_im/ui/screens/notifications_settings/events.cljs index ed383c6e49e2..368f2d951c93 100644 --- a/src/legacy/status_im/ui/screens/notifications_settings/events.cljs +++ b/src/legacy/status_im/ui/screens/notifications_settings/events.cljs @@ -18,7 +18,7 @@ (rf/defn notification-non-contacts {:events [:push-notifications/switch-non-contacts]} - [{:keys [db] :as cofx} enabled?] + [cofx enabled?] (let [method (if enabled? "wakuext_enablePushNotificationsFromContactsOnly" "wakuext_disablePushNotificationsFromContactsOnly")] @@ -32,7 +32,7 @@ (rf/defn notification-block-mentions {:events [:push-notifications/switch-block-mentions]} - [{:keys [db] :as cofx} enabled?] + [cofx enabled?] (let [method (if enabled? "wakuext_enablePushNotificationsBlockMentions" "wakuext_disablePushNotificationsBlockMentions")] @@ -48,7 +48,7 @@ (rf/defn notification-switch {:events [:push-notifications/switch]} - [{:keys [db] :as cofx} enabled?] + [cofx enabled?] (rf/merge cofx (if enabled? {:effects/push-notifications-enable nil} diff --git a/src/legacy/status_im/ui/screens/offline_messaging_settings/edit_mailserver/styles.cljs b/src/legacy/status_im/ui/screens/offline_messaging_settings/edit_mailserver/styles.cljs deleted file mode 100644 index 851bb08db471..000000000000 --- a/src/legacy/status_im/ui/screens/offline_messaging_settings/edit_mailserver/styles.cljs +++ /dev/null @@ -1,38 +0,0 @@ -(ns legacy.status-im.ui.screens.offline-messaging-settings.edit-mailserver.styles - (:require - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.utils.styles :as styles])) - -(def edit-mailserver-view - {:flex 1 - :margin-horizontal 16 - :margin-vertical 15}) - -(def qr-code - {:padding 16}) - -(def button-container - {:margin-top 8 - :margin-bottom 16 - :margin-horizontal 16}) - -(def button - {:height 52 - :align-items :center - :justify-content :center - :border-radius 8 - :ios {:opacity 0.9}}) - -(styles/def connect-button - (assoc button - :background-color - colors/blue)) - -(styles/def delete-button - (assoc button - :background-color - colors/red)) - -(def button-label - {:color colors/white - :font-size 17}) diff --git a/src/legacy/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs b/src/legacy/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs deleted file mode 100644 index 4a8e1421a3c7..000000000000 --- a/src/legacy/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs +++ /dev/null @@ -1,90 +0,0 @@ -(ns legacy.status-im.ui.screens.offline-messaging-settings.edit-mailserver.views - (:require-macros [legacy.status-im.utils.views :as views]) - (:require - [clojure.string :as string] - [legacy.status-im.qr-scanner.core :as qr-scanner] - [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.react :as react] - [legacy.status-im.ui.components.toolbar :as toolbar] - [legacy.status-im.ui.components.topbar :as topbar] - [legacy.status-im.ui.screens.offline-messaging-settings.edit-mailserver.styles :as styles] - [re-frame.core :as re-frame] - [utils.i18n :as i18n])) - -(defn connect-button - [id] - [react/touchable-highlight {:on-press #(re-frame/dispatch [:mailserver.ui/connect-pressed id])} - [react/view styles/button-container - [react/view - {:style styles/connect-button - :accessibility-label :mailserver-connect-button} - [react/text {:style styles/button-label} - (i18n/label :t/connect)]]]]) - -(defn delete-button - [id] - [react/touchable-highlight {:on-press #(re-frame/dispatch [:mailserver.ui/delete-pressed id])} - [react/view styles/button-container - [react/view - {:style styles/delete-button - :accessibility-label :mailserver-delete-button} - [react/text {:style styles/button-label} - (i18n/label :t/delete)]]]]) - -(views/defview edit-mailserver - [] - (views/letsubs [mailserver [:mailserver.edit/mailserver] - connected? [:mailserver.edit/connected?] - validation-errors [:mailserver.edit/validation-errors]] - (let [url (get-in mailserver [:url :value]) - id (get-in mailserver [:id :value]) - name (get-in mailserver [:name :value]) - is-valid? (and (not (string/blank? url)) - (not (string/blank? name)) - (empty? validation-errors)) - invalid-url? (contains? validation-errors :url)] - [react/keyboard-avoiding-view - {:style {:flex 1} - :ignore-offset true} - [topbar/topbar {:title (i18n/label (if id :t/mailserver-details :t/add-mailserver))}] - [react/scroll-view {:keyboard-should-persist-taps :handled} - [react/view styles/edit-mailserver-view - [react/view {:padding-vertical 8} - [quo/text-input - {:label (i18n/label :t/name) - :placeholder (i18n/label :t/specify-name) - :default-value name - :on-change-text #(re-frame/dispatch [:mailserver.ui/input-changed :name %]) - :auto-focus true}]] - [react/view - {:flex 1 - :padding-vertical 8} - [quo/text-input - {:label (i18n/label :t/mailserver-address) - :placeholder (i18n/label :t/mailserver-format) - :default-value url - :show-cancel false - :on-change-text #(re-frame/dispatch [:mailserver.ui/input-changed :url %]) - :bottom-value 0 - :error (when (and (not (string/blank? url)) - invalid-url?) - (i18n/label :t/invalid-format - {:format (i18n/label :t/mailserver-format)})) - :after {:icon :main-icons/qr - :on-press #(re-frame/dispatch - [::qr-scanner/scan-code - {:title (i18n/label :t/add-mailserver) - :handler :mailserver.callback/qr-code-scanned}])}}]] - (when (and id - (not connected?)) - [react/view - [connect-button id] - [delete-button id]])]] - [toolbar/toolbar - {:right - [quo/button - {:type :secondary - :after :main-icon/next - :disabled (not is-valid?) - :on-press #(re-frame/dispatch [:mailserver.ui/save-pressed])} - (i18n/label :t/save)]}]]))) diff --git a/src/legacy/status_im/ui/screens/offline_messaging_settings/styles.cljs b/src/legacy/status_im/ui/screens/offline_messaging_settings/styles.cljs index cdaef3841f02..5a1fa5e449a7 100644 --- a/src/legacy/status_im/ui/screens/offline_messaging_settings/styles.cljs +++ b/src/legacy/status_im/ui/screens/offline_messaging_settings/styles.cljs @@ -18,17 +18,6 @@ (def mailserver-item-name-text {:typography :title}) -(defn mailserver-icon-container - [connected?] - {:width 40 - :height 40 - :border-radius 20 - :background-color (if connected? - colors/blue - colors/black-transparent) - :align-items :center - :justify-content :center}) - (def switch-container {:height 52}) diff --git a/src/legacy/status_im/ui/screens/pairing/styles.cljs b/src/legacy/status_im/ui/screens/pairing/styles.cljs index 318eff85aadd..3126e8dc6c89 100644 --- a/src/legacy/status_im/ui/screens/pairing/styles.cljs +++ b/src/legacy/status_im/ui/screens/pairing/styles.cljs @@ -6,12 +6,6 @@ (def wrapper {:flex 1}) -(styles/def installation-item - {:flex-direction :row - :align-items :center - :ios {:height 64} - :android {:height 56}}) - (def installation-list {:padding-horizontal 16 :flex 1}) diff --git a/src/legacy/status_im/ui/screens/profile/components/sheets.cljs b/src/legacy/status_im/ui/screens/profile/components/sheets.cljs deleted file mode 100644 index d6eb2939b37d..000000000000 --- a/src/legacy/status_im/ui/screens/profile/components/sheets.cljs +++ /dev/null @@ -1,32 +0,0 @@ -(ns legacy.status-im.ui.screens.profile.components.sheets - (:require - [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.react :as react] - [legacy.status-im.ui.screens.profile.components.styles :as styles] - [re-frame.core :as re-frame] - [reagent.core :as reagent] - [utils.i18n :as i18n]) - (:require-macros [legacy.status-im.utils.views :as views])) - -(views/defview block-contact - [] - (views/letsubs [{:keys [public-key]} [:popover/popover] - in-progress? (reagent/atom false)] - [react/view {:style {:padding-top 16 :padding-horizontal 24 :padding-bottom 8}} - [react/text {:style styles/sheet-text} - (i18n/label :t/block-contact-details)] - [react/view {:align-items :center :margin-top 16} - [quo/button - {:theme :negative - :disabled @in-progress? - :loading @in-progress? - :accessibility-label :block-contact-confirm - :on-press #(do (reset! in-progress? true) - (re-frame/dispatch [:contact/block-contact public-key]))} - (i18n/label :t/block)] - [react/view {:height 8}] - [quo/button - {:type :secondary - :disabled @in-progress? - :on-press #(re-frame/dispatch [:hide-popover])} - (i18n/label :t/close)]]])) diff --git a/src/legacy/status_im/ui/screens/profile/components/styles.cljs b/src/legacy/status_im/ui/screens/profile/components/styles.cljs index ca4298c3cd5b..83856f85c132 100644 --- a/src/legacy/status_im/ui/screens/profile/components/styles.cljs +++ b/src/legacy/status_im/ui/screens/profile/components/styles.cljs @@ -1,6 +1,4 @@ -(ns legacy.status-im.ui.screens.profile.components.styles - (:require - [legacy.status-im.ui.components.colors :as colors])) +(ns legacy.status-im.ui.screens.profile.components.styles) ;; profile header elements @@ -14,15 +12,6 @@ :align-items :center :height 52}) -(def settings-item-icon - {:background-color colors/blue-light - :width 34 - :height 34 - :border-radius 34 - :margin-right 16 - :justify-content :center - :align-items :center}) - (def settings-item-text-wrapper {:flex 1 :flex-direction :row @@ -30,32 +19,3 @@ (def settings-item-text {:flex-wrap :nowrap}) - -(def settings-item-destructive - {:color colors/red}) - -(def settings-item-disabled - {:color colors/gray}) - -(def settings-item-value - {:flex 1 - :flex-wrap :nowrap - :text-align :right - :padding-right 10 - :color colors/gray}) - -;; shared profile styles - -(def profile - {:flex 1 - :flex-direction :column}) - -(def profile-form - {:padding-vertical 16}) - -;; sheets - -(def sheet-text - {:text-align :center - :line-height 22 - :font-size 15}) diff --git a/src/legacy/status_im/ui/screens/profile/components/views.cljs b/src/legacy/status_im/ui/screens/profile/components/views.cljs index 834102838f83..adec170fd45e 100644 --- a/src/legacy/status_im/ui/screens/profile/components/views.cljs +++ b/src/legacy/status_im/ui/screens/profile/components/views.cljs @@ -1,48 +1,11 @@ (ns legacy.status-im.ui.screens.profile.components.views (:require - [clojure.string :as string] [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.icons.icons :as icons] [legacy.status-im.ui.components.react :as react] - [legacy.status-im.ui.screens.profile.components.styles :as styles] - [utils.i18n :as i18n])) + [legacy.status-im.ui.screens.profile.components.styles :as styles])) ;; settings items elements -(defn settings-item - [{:keys [item-text label-kw value action-fn active? destructive? hide-arrow? - accessibility-label icon icon-content] - :or {value "" active? true}}] - [react/touchable-highlight - (cond-> {:on-press action-fn - :disabled (not active?)} - accessibility-label - (assoc :accessibility-label accessibility-label)) - [react/view styles/settings-item - (when icon - [react/view styles/settings-item-icon - [icons/icon icon {:color colors/blue}]]) - [react/view styles/settings-item-text-wrapper - [react/text - {:style (merge styles/settings-item-text - (when destructive? - styles/settings-item-destructive) - (when-not active? - styles/settings-item-disabled) - (when icon - {:font-size 17})) - :number-of-lines 1} - (or item-text (i18n/label label-kw))] - (when-not (string/blank? value) - [react/text - {:style styles/settings-item-value - :number-of-lines 1} - value])] - (if icon-content - icon-content - (when (and active? (not hide-arrow?)) - [icons/icon :main-icons/next {:color colors/gray-transparent-40}]))]]) - (defn settings-switch-item [{:keys [label-kw value action-fn active?] :or {active? true}}] diff --git a/src/legacy/status_im/ui/screens/profile/seed/styles.cljs b/src/legacy/status_im/ui/screens/profile/seed/styles.cljs index a9d20df3adca..3c333d2179dc 100644 --- a/src/legacy/status_im/ui/screens/profile/seed/styles.cljs +++ b/src/legacy/status_im/ui/screens/profile/seed/styles.cljs @@ -103,13 +103,3 @@ {:flex-direction :row :margin-top 16 :margin-bottom 32}) - -(def backup-seed - {:font-weight "700" - :text-align :center}) - -(def step-n - {:margin-top 5 - :font-size 14 - :text-align :center - :color colors/gray}) diff --git a/src/legacy/status_im/ui/screens/profile/user/edit_picture.cljs b/src/legacy/status_im/ui/screens/profile/user/edit_picture.cljs deleted file mode 100644 index d065b21ccf84..000000000000 --- a/src/legacy/status_im/ui/screens/profile/user/edit_picture.cljs +++ /dev/null @@ -1,62 +0,0 @@ -(ns legacy.status-im.ui.screens.profile.user.edit-picture - (:require - [legacy.status-im.ui.components.list.item :as list.item] - [legacy.status-im.ui.components.react :as react] - [re-frame.core :as re-frame] - [react-native.platform :as platform] - [status-im.config :as config] - [status-im.contexts.profile.settings.events] - [utils.i18n :as i18n] - [utils.re-frame :as rf])) - -(def crop-size 1000) -(def crop-opts - {:cropping true - :cropperCircleOverlay true - :width crop-size - :height crop-size}) - -(defn pick-pic - [] - (re-frame/dispatch [:bottom-sheet/hide-old]) - (when platform/ios? - (rf/dispatch [:alert-banners/hide])) - (react/show-image-picker - #(re-frame/dispatch [:profile.settings/save-profile-picture (.-path ^js %) 0 0 crop-size crop-size]) - crop-opts - #(rf/dispatch [:alert-banners/unhide]))) - -(defn take-pic - [] - (re-frame/dispatch [:bottom-sheet/hide-old]) - (when platform/ios? - (rf/dispatch [:alert-banners/hide])) - (react/show-image-picker-camera - #(re-frame/dispatch [:profile.settings/save-profile-picture (.-path ^js %) 0 0 crop-size crop-size]) - crop-opts - #(rf/dispatch [:alert-banners/unhide]))) - -(defn bottom-sheet - [has-picture] - (fn [] - [:<> - [list.item/list-item - {:accessibility-label :take-photo - :theme :accent - :icon :main-icons/camera - :title (i18n/label :t/profile-pic-take) - :on-press take-pic}] - [list.item/list-item - {:accessibility-label :pick-photo - :icon :main-icons/gallery - :theme :accent - :title (i18n/label :t/profile-pic-pick) - :on-press pick-pic}] - (when (and config/enable-remove-profile-picture? - has-picture) - [list.item/list-item - {:accessibility-label :remove-photo - :icon :main-icons/delete - :theme :accent - :title (i18n/label :t/profile-pic-remove) - :on-press #(re-frame/dispatch [:profile.settings/delete-profile-picture])}])])) diff --git a/src/legacy/status_im/ui/screens/profile/user/styles.cljs b/src/legacy/status_im/ui/screens/profile/user/styles.cljs deleted file mode 100644 index f22af2be1954..000000000000 --- a/src/legacy/status_im/ui/screens/profile/user/styles.cljs +++ /dev/null @@ -1,6 +0,0 @@ -(ns legacy.status-im.ui.screens.profile.user.styles) - -(def share-link-button - {:margin-top 12 - :margin-horizontal 16 - :margin-bottom 16}) diff --git a/src/legacy/status_im/ui/screens/profile/visibility_status/styles.cljs b/src/legacy/status_im/ui/screens/profile/visibility_status/styles.cljs index dd53ca0d18c0..7be5809c335a 100644 --- a/src/legacy/status_im/ui/screens/profile/visibility_status/styles.cljs +++ b/src/legacy/status_im/ui/screens/profile/visibility_status/styles.cljs @@ -3,19 +3,6 @@ [legacy.status-im.ui.components.colors :as colors] [quo.foundations.colors :as quo.colors])) -(defn visibility-status-button-container - [] - {:background-color (:interactive-02 @colors/theme) - :margin-left 16 - :border-radius 16 - :border-top-left-radius 4 - :align-self :flex-start - :flex-direction :row - :align-items :center - :justify-content :center - :padding 6 - :padding-right 12}) - (defn visibility-status-dot [{:keys [color size new-ui?]} theme] (if new-ui? @@ -31,68 +18,3 @@ :border-radius (/ size 2) :border-width 1 :border-color colors/white})) - -(defn visibility-status-profile-dot - [{:keys [color size border-width margin-left new-ui?]} theme] - (merge (visibility-status-dot {:color color - :size size - :new-ui? new-ui?} - theme) - {:margin-right 6 - :margin-left margin-left - :border-width border-width})) - -(defn visibility-status-text - [] - {:color (:text-01 @colors/theme) - :font-size 16 - :text-align :center}) - -(defn visibility-status-subtitle - [] - {:color (:text-02 @colors/theme) - :font-size 16 - :margin-left 22 - :margin-right 6}) - -(defn visibility-status-option - [] - {:flex-direction :row - :align-items :center}) - -(defn visibility-status-options - [scale position] - {:background-color (if (colors/dark?) - (:interactive-02 @colors/theme) - colors/white) - :border-radius 16 - :border-top-left-radius 4 - :justify-content :center - :align-self :flex-start - :left 16 - :top -76 - :padding-bottom 6 - :padding-top 8 - :transform [{:scaleY scale} - {:translateY position}]}) - -(defn visibility-status-popover-container - [] - {:position :absolute - :top 0 - :bottom 0 - :left 0 - :right 0}) - -(defn visibility-status-popover-ios-backdrop - [alpha-value] - {:flex 1 - :background-color colors/black-persist - :opacity alpha-value}) - -(defn visibility-status-popover-child-container - [window-height] - {:position :absolute - :height window-height - :left 0 - :right 0}) diff --git a/src/legacy/status_im/ui/screens/profile/visibility_status/utils.cljs b/src/legacy/status_im/ui/screens/profile/visibility_status/utils.cljs index 5895361110a2..a6db60e4fc6f 100644 --- a/src/legacy/status_im/ui/screens/profile/visibility_status/utils.cljs +++ b/src/legacy/status_im/ui/screens/profile/visibility_status/utils.cljs @@ -40,26 +40,6 @@ :title (i18n/label :t/status-inactive) :subtitle (i18n/label :t/status-inactive-subtitle)}}) -(def visibility-status-type-data-old - {constants/visibility-status-unknown - {:color colors/red - :title (i18n/label :t/error)} - constants/visibility-status-automatic - {:color colors/color-online - :title (i18n/label :t/status-automatic) - :subtitle (i18n/label :t/status-automatic-subtitle)} - constants/visibility-status-dnd - {:color colors/color-dnd - :title (i18n/label :t/status-dnd) - :subtitle (i18n/label :t/status-dnd-subtitle)} - constants/visibility-status-always-online - {:color colors/color-online - :title (i18n/label :t/status-always-online)} - constants/visibility-status-inactive - {:color colors/color-inactive - :title (i18n/label :t/status-inactive) - :subtitle (i18n/label :t/status-inactive-subtitle)}}) - (defn calculate-real-status-type [{:keys [status-type clock]}] (let [status-lifespan (if (= status-type constants/visibility-status-automatic) diff --git a/src/legacy/status_im/ui/screens/profile/visibility_status/views.cljs b/src/legacy/status_im/ui/screens/profile/visibility_status/views.cljs deleted file mode 100644 index b5936ad68745..000000000000 --- a/src/legacy/status_im/ui/screens/profile/visibility_status/views.cljs +++ /dev/null @@ -1,239 +0,0 @@ -(ns legacy.status-im.ui.screens.profile.visibility-status.views - (:require-macros [legacy.status-im.utils.views :as views]) - (:require - ["react-native" :refer (BackHandler)] - [legacy.status-im.ui.components.animation :as anim] - [legacy.status-im.ui.components.colors :as colors] - [legacy.status-im.ui.components.core :as quo] - [legacy.status-im.ui.components.react :as react] - [legacy.status-im.ui.screens.profile.visibility-status.styles :as styles] - [legacy.status-im.ui.screens.profile.visibility-status.utils :as utils] - [re-frame.core :as re-frame] - [react-native.core :as rn] - [react-native.platform :as platform] - [reagent.core :as reagent] - [status-im.constants :as constants] - [utils.re-frame :as rf])) - -;; === Code Related to visibility-status-button === - -(def button-ref (atom nil)) - -(defn dispatch-popover - [top] - (re-frame/dispatch [:show-visibility-status-popover {:top top}])) - -(defn dispatch-visibility-status-update - [status-type] - (re-frame/dispatch - [:visibility-status-updates/delayed-visibility-status-update status-type])) - -(defn calculate-button-height-and-dispatch-popover - [] - (.measure - ^js - @button-ref - (fn [_ _ _ _ _ page-y] - (dispatch-popover page-y)))) - -(defn profile-visibility-status-dot - [status-type color theme] - (let [automatic? (= status-type - constants/visibility-status-automatic) - [border-width margin-left size] (if automatic? [1 -10 12] [0 6 10]) - new-ui? true] - [:<> - (when automatic? - [rn/view - {:style (styles/visibility-status-profile-dot - {:color colors/color-inactive - :size size - :border-width border-width - :margin-left 6 - :new-ui? new-ui?} - theme)}]) - [rn/view - {:style (styles/visibility-status-profile-dot - {:color color - :size size - :border-width border-width - :margin-left margin-left - :new-ui? new-ui?} - theme)}]])) - -(defn visibility-status-button - [on-press props] - (let [logged-in? (rf/sub [:multiaccount/logged-in?]) - {:keys [status-type]} (rf/sub [:multiaccount/current-user-visibility-status]) - status-type (if (and logged-in? (nil? status-type)) - (do - (dispatch-visibility-status-update - constants/visibility-status-automatic) - constants/visibility-status-automatic) - status-type) - {:keys [color title]} (get utils/visibility-status-type-data-old status-type)] - [rn/touchable-opacity - (merge - {:on-press on-press - :accessibility-label :visibility-status-button - :style (styles/visibility-status-button-container) - :ref #(reset! button-ref ^js %)} - props) - [profile-visibility-status-dot status-type color] - [rn/text {:style (styles/visibility-status-text)} title]])) - -;; === Code Related to visibility-status-popover === -(def scale (anim/create-value 0)) -(def position (anim/create-value 0)) -(def alpha-value (anim/create-value 0)) - -(defn hide-options - [] - (anim/start - (anim/parallel - [(anim/timing scale - {:toValue 0 - :duration 140 - :useNativeDriver true}) - (anim/timing position - {:toValue 50 - :duration 210 - :useNativeDriver true}) - (anim/timing alpha-value - {:toValue 0 - :duration 200 - :useNativeDriver true})]))) - -(defn show-options - [] - (anim/start - (anim/parallel - [(anim/timing scale - {:toValue 1 - :duration 210 - :useNativeDriver true}) - (anim/timing position - {:toValue 80 - :duration 70 - :useNativeDriver true}) - (anim/timing alpha-value - {:toValue 0.4 - :duration 200 - :useNativeDriver true})]))) - -(defn status-option-pressed - [request-close status-type] - (request-close) - (dispatch-visibility-status-update status-type)) - -(defn status-option - [{:keys [request-close status-type]}] - (let [{:keys [color title subtitle]} - (get utils/visibility-status-type-data-old status-type)] - [rn/touchable-opacity - {:style {:padding 6} - :accessibility-label :visibility-status-option - :on-press #(status-option-pressed - request-close - status-type)} - [rn/view {:style (styles/visibility-status-option)} - [profile-visibility-status-dot status-type color] - [rn/text {:style (styles/visibility-status-text)} title]] - (when-not (nil? subtitle) - [rn/text {:style (styles/visibility-status-subtitle)} subtitle])])) - -(defn visibility-status-options - [request-close top] - [react/view - {:position :absolute - :top (int top)} - [visibility-status-button request-close {:ref nil :active-opacity 1}] - [react/animated-view - {:style - (styles/visibility-status-options scale position) - :accessibility-label :visibility-status-options} - [status-option - {:status-type constants/visibility-status-always-online - :request-close request-close}] - [quo/separator {:style {:margin-top 8}}] - [status-option - {:status-type constants/visibility-status-inactive - :request-close request-close}] - [quo/separator] - [status-option - {:status-type constants/visibility-status-automatic - :request-close request-close}]]]) - -(defn popover-view - [_ window-height] - (let [clear-timeout (atom nil) - current-popover (reagent/atom nil) - update? (reagent/atom nil) - request-close (fn [] - (reset! clear-timeout - (js/setTimeout - #(do (reset! current-popover nil) - (re-frame/dispatch - [:hide-visibility-status-popover])) - 200)) - (hide-options) - true) - on-show (fn [] - (show-options) - (when platform/android? - (.removeEventListener BackHandler - "hardwareBackPress" - request-close) - (.addEventListener BackHandler - "hardwareBackPress" - request-close))) - on-hide (fn [] - (when platform/android? - (.removeEventListener BackHandler - "hardwareBackPress" - request-close)))] - (reagent/create-class - {:UNSAFE_componentWillUpdate - (fn [_ [_ popover _]] - (when @clear-timeout (js/clearTimeout @clear-timeout)) - (cond - @update? - (do (reset! update? false) - (on-show)) - - (and @current-popover popover) - (do (reset! update? true) - (js/setTimeout #(reset! current-popover popover) 600) - (hide-options)) - - popover - (do (reset! current-popover popover) - (on-show)) - - :else - (do (reset! current-popover nil) - (on-hide)))) - :component-will-unmount on-hide - :reagent-render - (fn [] - (when @current-popover - (let [{:keys [top]} @current-popover] - [react/view - {:style (styles/visibility-status-popover-container)} - (when platform/ios? - [react/animated-view - {:style (styles/visibility-status-popover-ios-backdrop - alpha-value)}]) - [react/view - {:style (styles/visibility-status-popover-child-container - window-height)} - [react/touchable-highlight - {:style {:flex 1} - :on-press request-close} - [visibility-status-options request-close top]]]])))}))) - -(views/defview visibility-status-popover - [] - (views/letsubs [popover [:visibility-status-popover/popover] - {window-height :height} [:dimensions/window]] - [popover-view popover window-height])) diff --git a/src/legacy/status_im/ui/screens/reset_password/views.cljs b/src/legacy/status_im/ui/screens/reset_password/views.cljs index 91f99a738b67..f74a8e96e31b 100644 --- a/src/legacy/status_im/ui/screens/reset_password/views.cljs +++ b/src/legacy/status_im/ui/screens/reset_password/views.cljs @@ -1,91 +1,13 @@ (ns legacy.status-im.ui.screens.reset-password.views (:require - [legacy.status-im.multiaccounts.reset-password.core :as reset-password] [legacy.status-im.ui.components.colors :as colors] [legacy.status-im.ui.components.core :as quo] [legacy.status-im.ui.components.icons.icons :as icons] [legacy.status-im.ui.components.react :as react] - [legacy.status-im.ui.components.toolbar :as toolbar] [re-frame.core :as re-frame] - [utils.i18n :as i18n] - [utils.security.core :as security]) + [utils.i18n :as i18n]) (:require-macros [legacy.status-im.utils.views :refer [defview letsubs]])) -(defn input-field - [{:keys [id errors on-submit disabled? focus?] - :or {disabled? false focus? false}}] - [react/view {:style {:opacity (if disabled? 0.33 1)}} - [quo/text-input - {:placeholder (i18n/label id) - :default-value "" - :auto-focus focus? - :editable (not disabled?) - :accessibility-label id - :show-cancel false - :style {:margin-bottom 32} - :on-submit-editing on-submit - :on-change-text #(re-frame/dispatch [::reset-password/handle-input-change - id - (security/mask-data %)]) - :secure-text-entry true - :error (when-let [error (get errors id)] - (if (keyword? error) - (i18n/label error) - error))}]]) - -(defview reset-password - [] - (letsubs [{:keys [form-vals errors next-enabled? resetting?]} - [:multiaccount/reset-password-form-vals-and-errors]] - (let [{:keys [current-password - new-password]} - form-vals - on-submit #(re-frame/dispatch [::reset-password/reset form-vals])] - [react/keyboard-avoiding-view {:flex 1} - [react/view - {:style {:flex 1 - :justify-content :space-between}} - [react/view - {:style {:margin-top 32 - :padding-horizontal 16 - :padding-vertical 16}} - [input-field - {:id :current-password - :errors errors - :on-sumbit on-submit - :disabled? false - :focus? true}] - [input-field - {:id :new-password - :errors errors - :on-sumbit on-submit - :disabled? (zero? (count current-password))}] - [input-field - {:id :confirm-new-password - :errors errors - :on-sumbit on-submit - :disabled? (zero? (count new-password))}]] - [quo/text - {:color :secondary - :align :center - :size :small - :style {:padding-horizontal 16}} - (i18n/label :t/password-description)] - [toolbar/toolbar - {:show-border? true - :right - [quo/button - {:on-press on-submit - :accessibility-label :next-button - :disabled (or (not next-enabled?) - ;; disable on resetting? so the user cannot press the next - ;; button recklessly - ;; https://github.com/status-im/status-mobile/pull/12245#issuecomment-874827573 - resetting?) - :type :secondary - :after :main-icons/next} - (i18n/label :t/next)]}]]]))) - (defview reset-password-popover [] (letsubs [{:keys [resetting?]} [:multiaccount/reset-password-form-vals-and-errors]] diff --git a/src/legacy/status_im/ui/screens/screens.cljs b/src/legacy/status_im/ui/screens/screens.cljs index 2d75645e56b6..f2ee4efeddfd 100644 --- a/src/legacy/status_im/ui/screens/screens.cljs +++ b/src/legacy/status_im/ui/screens/screens.cljs @@ -5,7 +5,6 @@ [legacy.status-im.ui.screens.appearance.views :as appearance] [legacy.status-im.ui.screens.backup-settings.view :as backup-settings] [legacy.status-im.ui.screens.bug-report :as bug-report] - [legacy.status-im.ui.screens.communities.invite :as communities.invite] [legacy.status-im.ui.screens.communities.members :as members] [legacy.status-im.ui.screens.default-sync-period-settings.view :as default-sync-period-settings] [legacy.status-im.ui.screens.fleet-settings.views :as fleet-settings] @@ -13,14 +12,12 @@ [legacy.status-im.ui.screens.help-center.views :as help-center] [legacy.status-im.ui.screens.log-level-settings.views :as log-level-settings] [legacy.status-im.ui.screens.notifications-settings.views :as notifications-settings] - [legacy.status-im.ui.screens.offline-messaging-settings.edit-mailserver.views :as edit-mailserver] [legacy.status-im.ui.screens.offline-messaging-settings.views :as offline-messaging-settings] [legacy.status-im.ui.screens.pairing.views :as pairing] [legacy.status-im.ui.screens.peers-stats :as peers-stats] [legacy.status-im.ui.screens.profile.seed.views :as profile.seed] [legacy.status-im.ui.screens.profile.user.views :as profile.user] [legacy.status-im.ui.screens.progress.views :as progress] - [legacy.status-im.ui.screens.reset-password.views :as reset-password] [legacy.status-im.ui.screens.rpc-usage-info :as rpc-usage-info] [legacy.status-im.ui.screens.sync-settings.views :as sync-settings] [legacy.status-im.ui.screens.wakuv2-settings.edit-node.views :as edit-wakuv2-node] @@ -54,9 +51,6 @@ :options {:insets {:top? true}} :component members/legacy-members-container} - {:name :legacy-invite-people-community - :options {:insets {:bottom? true :top? true}} - :component communities.invite/legacy-invite} ;;SETTINGS {:name :legacy-notifications @@ -122,9 +116,6 @@ {:name :offline-messaging-settings :options {:insets {:top? true}} :component offline-messaging-settings/offline-messaging-settings} - {:name :edit-mailserver - :options {:insets {:top? true}} - :component edit-mailserver/edit-mailserver} {:name :rpc-usage-info :options {:topBar (topbar-options :t/rpc-usage-info) :insets {:top? true}} @@ -144,10 +135,6 @@ {:name :backup-seed :options {:insets {:top? platform/android? :bottom? true}} :component profile.seed/backup-seed} - {:name :reset-password - :options {:topBar (topbar-options :t/reset-password) - :insets {:top? true}} - :component reset-password/reset-password} {:name :default-sync-period-settings :options {:topBar (topbar-options :t/default-sync-period) :insets {:top? true}} diff --git a/src/legacy/status_im/ui/screens/wakuv2_settings/styles.cljs b/src/legacy/status_im/ui/screens/wakuv2_settings/styles.cljs index ee729c6f91c2..9944e6874cd7 100644 --- a/src/legacy/status_im/ui/screens/wakuv2_settings/styles.cljs +++ b/src/legacy/status_im/ui/screens/wakuv2_settings/styles.cljs @@ -17,7 +17,3 @@ (def node-item-name-text {:font-size 17}) - -(def switch-container - {:height 50 - :padding-left 15}) diff --git a/src/legacy/status_im/utils/async.cljs b/src/legacy/status_im/utils/async.cljs index 1e94f4b9f6c7..a4ac0473a1e1 100644 --- a/src/legacy/status_im/utils/async.cljs +++ b/src/legacy/status_im/utils/async.cljs @@ -14,13 +14,6 @@ ;; This wrapping is required as core.async macro replaces tries and catch with ;; https://github.com/clojure/core.async/blob/18d2f903b169c681ed008dd9545dc33458604b89/src/main/clojure/cljs/core/async/impl/ioc_helpers.cljs#L74 ;; and this does not seem to play nice with desktop, and the error is bubble up killing the go-loop -(defn run-task - [f] - (try - (f) - (catch :default e - (log/error "failed to run task" e)))) - (defn chunked-pipe! "Connects input channel to the output channel with time-based chunking. `flush-time` parameter decides for how long we are waiting to accumulate @@ -42,28 +35,10 @@ (async/close! output-ch)) (recur acc (seq acc))))))) -(defn task-queue - "Creates `core.async` channel which will process 0 arg functions put there in serial fashion. - Takes the same argument/s as `core.async/chan`, those arguments will be delegated to the - channel constructor. - Returns task-queue where tasks represented by 0 arg task functions can be put for processing." - [& args] - (let [queue (apply async/chan args)] - (async/go-loop [task-fn (async/ (shell/sh "bash" "./scripts/version/build_no.sh") diff --git a/src/legacy/status_im/utils/core.cljc b/src/legacy/status_im/utils/core.cljc index 4a7d7abc3820..60f00bb30d2f 100644 --- a/src/legacy/status_im/utils/core.cljc +++ b/src/legacy/status_im/utils/core.cljc @@ -18,18 +18,3 @@ s)) (def truncate-str (memoize truncate-str-memo)) - -(defn first-index - "Returns first index in coll where predicate on coll element is truthy" - [pred coll] - (->> coll - (keep-indexed (fn [idx e] - (when (pred e) - idx))) - first)) - -(defn index-by - "Given a collection and a unique key function, returns a map that indexes the collection. - Similar to group-by except that the map values are single objects (depends on key uniqueness)." - [k coll] - (into {} (map #(vector (k %) %) coll))) diff --git a/src/legacy/status_im/utils/deprecated_types.cljs b/src/legacy/status_im/utils/deprecated_types.cljs index faea22bd1d37..d4661697313b 100644 --- a/src/legacy/status_im/utils/deprecated_types.cljs +++ b/src/legacy/status_im/utils/deprecated_types.cljs @@ -7,12 +7,6 @@ ;; NOTE(19/12/22 yqrashawn) this namespace has been moved to the utils.transforms namespace, ;; we keep this only for old (status 1.0) code, can be removed with old code later -(defn to-string - [s] - (if (keyword? s) - (name s) - s)) - (defn js->clj [data] (cljs.core/js->clj data :keywordize-keys true)) @@ -21,10 +15,6 @@ [data spaces] (.stringify js/JSON (clj-bean/->js data) nil spaces)) -(defn js->pretty-json - [data] - (.stringify js/JSON data nil 2)) - (defn clj->json [data] (clj->pretty-json data 0)) @@ -37,16 +27,3 @@ (catch js/Error _ (when (string? json) json))))) -(defn json->js - [json] - (when-not (= json "undefined") - (try - (.parse js/JSON json) - (catch js/Error _ - (when (string? json) json))))) - -(def serialize clj->json) -(defn deserialize - [o] - (try (json->clj o) - (catch :default _ nil))) diff --git a/src/legacy/status_im/utils/dimensions.cljs b/src/legacy/status_im/utils/dimensions.cljs index af79add73b8b..d49a834716cb 100644 --- a/src/legacy/status_im/utils/dimensions.cljs +++ b/src/legacy/status_im/utils/dimensions.cljs @@ -1,13 +1,6 @@ (ns legacy.status-im.utils.dimensions (:require - [legacy.status-im.ui.components.react :as react] - [re-frame.core :as re-frame])) - -(defn add-event-listener - [] - (.addEventListener ^js react/dimensions - "change" - #(re-frame/dispatch-sync [:update-window-dimensions %]))) + [legacy.status-im.ui.components.react :as react])) (defn window ([] diff --git a/src/legacy/status_im/utils/image.cljs b/src/legacy/status_im/utils/image.cljs deleted file mode 100644 index 2537bd22bb67..000000000000 --- a/src/legacy/status_im/utils/image.cljs +++ /dev/null @@ -1,9 +0,0 @@ -(ns legacy.status-im.utils.image - (:require - [clojure.string :as string])) - -(defn source - [photo-path] - (when-not (and (not (string/blank? photo-path)) - (string/starts-with? photo-path "contacts://")) - {:uri photo-path})) diff --git a/src/legacy/status_im/utils/label.cljs b/src/legacy/status_im/utils/label.cljs deleted file mode 100644 index 447e06f60a79..000000000000 --- a/src/legacy/status_im/utils/label.cljs +++ /dev/null @@ -1,25 +0,0 @@ -(ns legacy.status-im.utils.label - (:require - [utils.i18n :as i18n])) - -(defn stringify - [keyword-or-number] - (cond - (string? keyword-or-number) - keyword-or-number - - (and (qualified-keyword? keyword-or-number) - (= "t" (namespace keyword-or-number))) - (i18n/label keyword-or-number) - - (and (qualified-keyword? keyword-or-number) - (not= "t" (namespace keyword-or-number))) - (str (namespace keyword-or-number) "/" (name keyword-or-number)) - - (simple-keyword? keyword-or-number) - (name keyword-or-number) - - (number? keyword-or-number) - (str keyword-or-number) - - :else nil)) diff --git a/src/legacy/status_im/utils/logging/core.cljs b/src/legacy/status_im/utils/logging/core.cljs index 270ae5ef9926..51092ae6808b 100644 --- a/src/legacy/status_im/utils/logging/core.cljs +++ b/src/legacy/status_im/utils/logging/core.cljs @@ -192,7 +192,7 @@ (rf/defn share-logs-file {:events [::share-logs-file]} - [{:keys [db] :as cofx} archive-uri] + [cofx archive-uri] (rf/merge cofx (dialog-closed) @@ -202,9 +202,9 @@ (rf/defn details {:events [:logging/report-details]} - [{:keys [db]} key value] + [{:keys [db]} log-key value] {:db (-> db - (assoc-in [:bug-report/details key] value) + (assoc-in [:bug-report/details log-key] value) (dissoc :bug-report/description-error))}) (def min-description-lenght 6) @@ -218,7 +218,7 @@ (rf/defn submit-report {:events [:logging/submit-report]} - [{:keys [db] :as cofx} details steps] + [{:keys [db] :as cofx}] (if-let [error (validate-description db)] {:db (assoc db :bug-report/description-error error)} (rf/merge @@ -247,7 +247,7 @@ (rf/defn submit-gh-issue {:events [:logging/submit-gh-issue]} - [{:keys [db] :as cofx} details steps] + [{:keys [db] :as cofx}] (rf/merge cofx {:db (dissoc db :bug-report/details)} diff --git a/src/legacy/status_im/utils/mobile_sync.cljs b/src/legacy/status_im/utils/mobile_sync.cljs index 2a4cfc89a0d7..66a7da1662b2 100644 --- a/src/legacy/status_im/utils/mobile_sync.cljs +++ b/src/legacy/status_im/utils/mobile_sync.cljs @@ -1,9 +1,5 @@ (ns legacy.status-im.utils.mobile-sync) -(defn cellular? - [network-type] - (= network-type "cellular")) - (defn syncing-allowed? [db] (let [network (:network/type db) diff --git a/src/legacy/status_im/utils/name.cljs b/src/legacy/status_im/utils/name.cljs deleted file mode 100644 index dd7818dc267d..000000000000 --- a/src/legacy/status_im/utils/name.cljs +++ /dev/null @@ -1,33 +0,0 @@ -(ns legacy.status-im.utils.name - (:require - [clojure.string :as string])) - -(defn too-long? - [name max-len] - (> (count name) max-len)) - -(defn max-name - [name max-len] - (let [names (string/split name " ")] - (first - (reduce (fn [[name done] next-name] - (if done - name - (let [new-name (string/join " " [name next-name])] - (if (too-long? new-name max-len) - (let [new-name' (str name " " (first next-name) ".")] - (if (too-long? new-name' max-len) - [name true] - [new-name' true])) - [new-name])))) - [(first names)] - (rest names))))) - -(defn shortened-name - [name max-len] - (if (> (count name) max-len) - (let [name' (max-name name max-len)] - (if (too-long? name' max-len) - (str (string/trim (subs name 0 max-len)) "...") - name')) - name)) diff --git a/src/legacy/status_im/utils/priority_map.cljs b/src/legacy/status_im/utils/priority_map.cljs deleted file mode 100644 index 662ed9efef6e..000000000000 --- a/src/legacy/status_im/utils/priority_map.cljs +++ /dev/null @@ -1,267 +0,0 @@ -(ns legacy.status-im.utils.priority-map - (:require - [cljs.core :as core] - [cljs.reader :refer [register-tag-parser!]]) - (:require-macros [cljs.core :as coreclj])) - -;; from -;; https://github.com/tailrecursion/cljs-priority-map/blob/master/src/cljs/tailrecursion/priority_map.cljs -;; fixing `vals` and `keys` function - -#_{:clj-kondo/ignore [:shadowed-var]} -(deftype PersistentPriorityMap [priority->set-of-items item->priority meta keyfn ^:mutable __hash] - IPrintWithWriter - (-pr-writer [coll writer opts] - (let [pr-pair (fn [keyval] - (pr-sequential-writer writer #'cljs.core/pr-writer "" " " "" opts keyval))] - (pr-sequential-writer writer - pr-pair - "#legacy.status-im.utils.priority-map {" - ", " - "}" - opts - coll))) - - IWithMeta - (-with-meta [_this meta] - (PersistentPriorityMap. priority->set-of-items item->priority meta keyfn __hash)) - - IMeta - (-meta [_this] meta) - - ICollection - (-conj [this entry] - (if (vector? entry) - (-assoc this (-nth entry 0) (-nth entry 1)) - (reduce -conj this entry))) - - IEmptyableCollection - (-empty [_this] - #_{:clj-kondo/ignore [:unresolved-symbol]} - (with-meta - legacy.status-im.utils.priority-map.PersistentPriorityMap.EMPTY - meta)) - - IEquiv - (-equiv [_this other] - (-equiv item->priority other)) - - IHash - (-hash [this] - (coreclj/caching-hash this core/hash-unordered-coll __hash)) - - ISeqable - (-seq [_this] - (if keyfn - (seq (for [[_ item-set] priority->set-of-items - item item-set] - (MapEntry. item (item->priority item) nil))) - (seq (for [[priority item-set] priority->set-of-items - item item-set] - (MapEntry. item priority nil))))) - - IReversible - (-rseq [_coll] - (if keyfn - (seq (for [[_ item-set] (rseq priority->set-of-items) - item item-set] - (MapEntry. item (item->priority item) nil))) - (seq (for [[priority item-set] (rseq priority->set-of-items) - item item-set] - (MapEntry. item priority nil))))) - - ICounted - (-count [_this] - (count item->priority)) - - ILookup - (-lookup [_this item] - (get item->priority item)) - (-lookup [_coll item not-found] - (get item->priority item not-found)) - - IStack - (-peek [_this] - (when-not (zero? (count item->priority)) - (let [f (first priority->set-of-items) - item (first (val f))] - (if keyfn - [item (item->priority item)] - [item (key f)])))) - (-pop [_this] - (if (zero? (count item->priority)) - (throw (js/Error. "Can't pop empty priority map")) - (let [f (first priority->set-of-items) - item-set (val f) - item (first item-set) - priority-key (key f)] - (if (= (count item-set) 1) - (PersistentPriorityMap. - (dissoc priority->set-of-items priority-key) - (dissoc item->priority item) - meta - keyfn - nil) - (PersistentPriorityMap. - (assoc priority->set-of-items priority-key (disj item-set item)) - (dissoc item->priority item) - meta - keyfn - nil))))) - - IAssociative - (-assoc [this item priority] - (if-let [current-priority (get item->priority item nil)] - (if (= current-priority priority) - this - (let [priority-key (keyfn priority) - current-priority-key (keyfn current-priority) - item-set (get priority->set-of-items current-priority-key)] - (if (= (count item-set) 1) - (PersistentPriorityMap. - (assoc (dissoc priority->set-of-items current-priority-key) - priority-key - (conj (get priority->set-of-items priority-key #{}) item)) - (assoc item->priority item priority) - meta - keyfn - nil) - (PersistentPriorityMap. - (assoc priority->set-of-items - current-priority-key - (disj (get priority->set-of-items current-priority-key) item) - priority-key - (conj (get priority->set-of-items priority-key #{}) item)) - (assoc item->priority item priority) - meta - keyfn - nil)))) - (let [priority-key (keyfn priority)] - (PersistentPriorityMap. - (assoc priority->set-of-items - priority-key - (conj (get priority->set-of-items priority-key #{}) item)) - (assoc item->priority item priority) - meta - keyfn - nil)))) - - (-contains-key? [_this item] - (contains? item->priority item)) - - IMap - (-dissoc [this item] - (let [priority (item->priority item ::not-found)] - (if (= priority ::not-found) - this - (let [priority-key (keyfn priority) - item-set (priority->set-of-items priority-key)] - (if (= (count item-set) 1) - (PersistentPriorityMap. - (dissoc priority->set-of-items priority-key) - (dissoc item->priority item) - meta - keyfn - nil) - (PersistentPriorityMap. - (assoc priority->set-of-items priority-key (disj item-set item)) - (dissoc item->priority item) - meta - keyfn - nil)))))) - - ISorted - (-sorted-seq [this ascending?] - ((if ascending? seq rseq) this)) - (-sorted-seq-from [_this k ascending?] - (let [sets (if ascending? - (subseq priority->set-of-items >= k) - (rsubseq priority->set-of-items <= k))] - (if keyfn - (seq (for [[_ item-set] sets - item item-set] - [item (item->priority item)])) - (seq (for [[priority item-set] sets - item item-set] - [item priority]))))) - (-entry-key [_this entry] - (keyfn (val entry))) - (-comparator [_this] compare) - - IFn - (-invoke [this item] - (-lookup this item)) - (-invoke [this item not-found] - (-lookup this item not-found))) - -#_{:clj-kondo/ignore [:unresolved-symbol]} -(set! legacy.status-im.utils.priority-map.PersistentPriorityMap.EMPTY - (PersistentPriorityMap. (sorted-map) {} {} identity nil)) - -(defn- pm-empty-by - [f-comparator] - (PersistentPriorityMap. (sorted-map-by f-comparator) {} {} identity nil)) - -(defn- pm-empty-keyfn - ([keyfn] - (PersistentPriorityMap. (sorted-map) {} {} keyfn nil)) - ([keyfn f-comparator] - (PersistentPriorityMap. (sorted-map-by f-comparator) {} {} keyfn nil))) - -(defn- read-priority-map - [elems] - (if (map? elems) - (into PersistentPriorityMap.EMPTY elems) - (throw (js/Error "Priority map literal expects a map for its elements.")))) - -(register-tag-parser! "legacy.status-im.utils.priority-map" read-priority-map) - -(defn priority-map - "keyval => key val - Returns a new priority map with supplied mappings." - ([& keyvals] - #_{:clj-kondo/ignore [:unresolved-symbol]} - (loop [in (seq keyvals) - out legacy.status-im.utils.priority-map.PersistentPriorityMap.EMPTY] - (if in - (recur (nnext in) (assoc out (first in) (second in))) - out)))) - -(defn priority-map-by - "keyval => key val - Returns a new priority map with supplied - mappings, using the supplied comparator." - ([f-comparator & keyvals] - (loop [in (seq keyvals) - out (pm-empty-by f-comparator)] - (if in - (recur (nnext in) (assoc out (first in) (second in))) - out)))) - -(defn priority-map-keyfn - "keyval => key val - Returns a new priority map with supplied - mappings, using the supplied keyfn." - ([keyfn & keyvals] - (loop [in (seq keyvals) - out (pm-empty-keyfn keyfn)] - (if in - (recur (nnext in) (assoc out (first in) (second in))) - out)))) - -(defn priority-map-keyfn-by - "keyval => key val - Returns a new priority map with supplied - mappings, using the supplied keyfn and comparator." - ([keyfn f-comparator & keyvals] - (loop [in (seq keyvals) - out (pm-empty-keyfn keyfn f-comparator)] - (if in - (recur (nnext in) (assoc out (first in) (second in))) - out)))) - -(def empty-message-map - (priority-map-keyfn-by :clock-value >)) - -(def empty-transaction-map - (priority-map-keyfn-by :block #(< (int %1) (int %2)))) diff --git a/src/legacy/status_im/utils/transducers_test.cljs b/src/legacy/status_im/utils/transducers_test.cljs index 7d6fb51ae31c..150a487587f0 100644 --- a/src/legacy/status_im/utils/transducers_test.cljs +++ b/src/legacy/status_im/utils/transducers_test.cljs @@ -3,20 +3,6 @@ [cljs.test :refer-macros [deftest is testing]] [legacy.status-im.utils.transducers :as transducers])) -(def preview-call-1 - {:jail-id 1 - :path [:preview] - :params {:chat-id 1} - :callback (fn [] - [[:msg-id 1]])}) - -(def preview-call-2 - {:jail-id 1 - :path [:preview] - :params {:chat-id 1} - :callback (fn [] - [[:msg-id 2]])}) - (def jail-calls '({:jail-id 1 :path [:suggestions] diff --git a/src/legacy/status_im/utils/utils.cljs b/src/legacy/status_im/utils/utils.cljs index c5061d0e6b36..57b72d230c93 100644 --- a/src/legacy/status_im/utils/utils.cljs +++ b/src/legacy/status_im/utils/utils.cljs @@ -2,8 +2,6 @@ (:require ["react-native" :as react-native] ["react-native-background-timer" :default background-timer] - [clojure.string :as string] - [goog.string :as gstring] [re-frame.core :as re-frame] [utils.address :as address] [utils.ethereum.eip.eip55 :as eip55] @@ -71,10 +69,6 @@ [cb ms] (.setTimeout background-timer cb ms)) -(defn clear-timeout - [id] - (.clearTimeout background-timer id)) - (defn set-interval [cb ms] (.setInterval background-timer cb ms)) @@ -90,13 +84,6 @@ (when (and ms dispatch) (set-timeout #(re-frame/dispatch dispatch) ms))))) -(re-frame/reg-fx - ::clear-timeouts - (fn [ids] - (doseq [id ids] - (when id - (clear-timeout id))))) - (defn get-shortened-address "Takes first and last 4 digits from address including leading 0x and adds unicode ellipsis in between" @@ -108,24 +95,3 @@ [address] (when address (get-shortened-address (eip55/address->checksum (address/normalized-hex address))))) - -;;TODO (14/11/22 flexsurfer) haven't moved yet -(defn format-decimals - [amount places] - (let [decimal-part (get (string/split (str amount) ".") 1)] - (if (> (count decimal-part) places) - (gstring/format (str "%." places "f") amount) - (or (str amount) 0)))) - -(defn safe-nth - [coll index] - (when (number? index) - (nth coll index))) - -(defn svg? - [some-string] - (string/ends-with? some-string ".svg")) - -(defn exclude-svg-resources - [lst] - (remove svg? lst)) diff --git a/src/legacy/status_im/utils/utils_test.cljs b/src/legacy/status_im/utils/utils_test.cljs index 6e51140cc977..a6aa154ec28d 100644 --- a/src/legacy/status_im/utils/utils_test.cljs +++ b/src/legacy/status_im/utils/utils_test.cljs @@ -1,26 +1,13 @@ (ns legacy.status-im.utils.utils-test (:require [cljs.test :refer-macros [deftest is]] - [legacy.status-im.utils.core :as u] - [legacy.status-im.utils.utils :as uu])) + [legacy.status-im.utils.core :as sut])) (deftest truncate-str-test - (is (= (u/truncate-str "Long string" 7) "Long...")) ; threshold is less then string length - (is (= (u/truncate-str "Long string" 7 true) "Lo...ng")) ; threshold is less then string length - ; (truncate middle) - (is (= (u/truncate-str "Long string" 11) "Long string")) ; threshold is the same as string length - (is (= (u/truncate-str "Long string" 20) "Long string"))) ; threshold is more then string length + (is (= (sut/truncate-str "Long string" 7) "Long...")) ; threshold is less then string length + (is (= (sut/truncate-str "Long string" 7 true) "Lo...ng")) ; threshold is less then string length + ; (truncate middle) + (is (= (sut/truncate-str "Long string" 11) "Long string")) ; threshold is the same as string + ; length + (is (= (sut/truncate-str "Long string" 20) "Long string"))) ; threshold is more then string length -(deftest first-index-test - (is (= 2 - (u/first-index (partial = :test) - '(:a :b :test :c :test)))) - (is (= nil - (u/first-index (partial = :test) - '(:a :b :c))))) - -(deftest format-decimals-test - (is (= "1" (uu/format-decimals 1 5))) - (is (= "1.1" (uu/format-decimals 1.1 5))) - (is (= "1.111111" (uu/format-decimals 1.111111 7))) - (is (= "1.1" (uu/format-decimals 1.111 1)))) diff --git a/src/legacy/status_im/visibility_status_updates/core.cljs b/src/legacy/status_im/visibility_status_updates/core.cljs index 95e0b49d3cc8..c6188b781380 100644 --- a/src/legacy/status_im/visibility_status_updates/core.cljs +++ b/src/legacy/status_im/visibility_status_updates/core.cljs @@ -101,7 +101,7 @@ (rf/defn update-visibility-status {:events [:visibility-status-updates/update-visibility-status]} - [{:keys [db] :as cofx} status-type] + [{:keys [db]} status-type] {:db (update-in db [:profile/profile :current-user-visibility-status] merge @@ -113,10 +113,10 @@ (rf/defn send-visibility-status-updates? {:events [:visibility-status-updates/send-visibility-status-updates?]} - [cofx val] + [cofx value] (multiaccounts.update/multiaccount-update cofx :send-status-updates? - val + value {})) (rf/defn visibility-status-option-pressed @@ -142,7 +142,7 @@ (rf/defn delayed-visibility-status-update {:events [:visibility-status-updates/delayed-visibility-status-update]} - [{:keys [db]} status-type] + [_ status-type] {:dispatch-later [{:ms 200 :dispatch @@ -150,13 +150,13 @@ (rf/defn peers-summary-change [{:keys [db] :as cofx} peers-count] - (let [send-visibility-status-updates? + (let [send-updates? (get-in db [:profile/profile :send-status-updates?]) status-type (get-in db [:profile/profile :current-user-visibility-status :status-type])] (when (and (> peers-count 0) - send-visibility-status-updates? + send-updates? (= status-type constants/visibility-status-inactive)) (rf/merge cofx {:dispatch-later [{:ms 1000 diff --git a/src/legacy/status_im/waku/core.cljs b/src/legacy/status_im/waku/core.cljs index 84c15b52575b..5c9fb33c8d87 100644 --- a/src/legacy/status_im/waku/core.cljs +++ b/src/legacy/status_im/waku/core.cljs @@ -16,7 +16,7 @@ (rf/defn set-input {:events [:wakuv2.ui/input-changed]} - [{:keys [db] :as cofx} input-key value] + [{:keys [db]} input-key value] {:db (assoc-in db [:wakuv2-nodes/manage input-key] {:value value @@ -81,7 +81,7 @@ (rf/defn save-all-pressed {:events [:wakuv2.ui/save-all-pressed]} - [{:keys [db] :as cofx}] + [_cofx] {:ui/show-confirmation {:title (i18n/label :t/close-app-title) :content (i18n/label :t/wakuv2-change-nodes) @@ -92,7 +92,7 @@ (rf/defn save-all {:events [:wakuv2.ui/save-all-confirmed]} - [{:keys [db] :as cofx}] + [{:keys [db]}] (let [new-nodes (->> (:wakuv2-nodes/list db) vals (map #(vector (:name %1) (:address %1))) diff --git a/src/native_module/push_notifications.cljs b/src/native_module/push_notifications.cljs index 408cf0d97ea9..c0c7a7108ae3 100644 --- a/src/native_module/push_notifications.cljs +++ b/src/native_module/push_notifications.cljs @@ -16,10 +16,6 @@ [chat-id] (.clearMessageNotifications ^js (push-notification) chat-id)) -(defn clear-all-message-notifications - [] - (.clearAllMessageNotifications ^js (push-notification))) - (defn create-channel [{:keys [channel-id channel-name]}] (.createChannel ^js (push-notification) diff --git a/src/quo/components/colors/color/view.cljs b/src/quo/components/colors/color/view.cljs index 76d36724fb92..cce2022a66c1 100644 --- a/src/quo/components/colors/color/view.cljs +++ b/src/quo/components/colors/color/view.cljs @@ -19,6 +19,7 @@ :as props}] (let [theme (quo.theme/use-theme) border? (and (not blur?) (not selected?)) + hex-color (if (= :feng-shui color) (colors/theme-colors colors/neutral-100 colors/white theme) (colors/theme-colors (colors/custom-color color 50) diff --git a/src/quo/components/common/not_implemented/style.cljs b/src/quo/components/common/not_implemented/style.cljs deleted file mode 100644 index 0c348e48d585..000000000000 --- a/src/quo/components/common/not_implemented/style.cljs +++ /dev/null @@ -1,13 +0,0 @@ -(ns quo.components.common.not-implemented.style - (:require - [quo.foundations.colors :as colors])) - -(defn text - [blur? theme] - {:border-color :red - :border-width 1 - :color (if blur? - colors/white - (colors/theme-colors colors/neutral-100 - colors/white - theme))}) diff --git a/src/quo/components/common/not_implemented/view.cljs b/src/quo/components/common/not_implemented/view.cljs deleted file mode 100644 index 0cbeea575ec5..000000000000 --- a/src/quo/components/common/not_implemented/view.cljs +++ /dev/null @@ -1,11 +0,0 @@ -(ns quo.components.common.not-implemented.view - (:require - [quo.components.common.not-implemented.style :as style] - [quo.theme :as quo.theme] - [react-native.core :as rn])) - -(defn view - [{:keys [blur?]}] - (let [theme (quo.theme/use-theme)] - [rn/text {:style (style/text blur? theme)} - "not implemented"])) diff --git a/src/quo/components/community/community_list_view.cljs b/src/quo/components/community/community_list_view.cljs index 5e359006d803..cf4ad50943a0 100644 --- a/src/quo/components/community/community_list_view.cljs +++ b/src/quo/components/community/community_list_view.cljs @@ -38,49 +38,6 @@ unread-messages? [unread-grey-dot :unviewed-messages-public])]) -(defn communities-list-view-item - [{:keys [customization-color] :as props} - {:keys [name locked? status muted unread-messages? unread-mentions-count community-icon tokens]}] - (let [theme (quo.theme/use-theme)] - [rn/view - {:style (merge (style/community-card 16 theme) - {:margin-bottom 12})} - [rn/touchable-highlight - (merge {:style {:height 56 - :border-radius 16}} - props) - [rn/view {:style style/detail-container} - [rn/view (style/list-info-container) - [community-icon/community-icon - {:images community-icon} 32] - [rn/view - {:flex 1 - :margin-horizontal 12} - [text/text - {:weight :semi-bold - :size :paragraph-1 - :accessibility-label :community-name-text - :number-of-lines 1 - :ellipsize-mode :tail - :style {:color (when muted - (colors/theme-colors - colors/neutral-40 - colors/neutral-60 - theme))}} - name] - [community-view/community-stats-column - {:type :list-view}]] - (if (= status :gated) - [community-view/permission-tag-container - {:locked? locked? - :tokens tokens}] - [notification-view - {:customization-color customization-color - :theme theme - :muted? muted - :unread-mentions-count unread-mentions-count - :unread-messages? unread-messages?}])]]]])) - (defn- title-color [unread-messages? muted theme] (cond diff --git a/src/quo/components/community/style.cljs b/src/quo/components/community/style.cljs index 3a2b2bf33889..492d62c6cf93 100644 --- a/src/quo/components/community/style.cljs +++ b/src/quo/components/community/style.cljs @@ -68,14 +68,6 @@ colors/neutral-90 theme)}) -(defn list-info-container - [] - {:flex-direction :row - :border-radius 16 - :padding-horizontal 12 - :align-items :center - :padding-vertical 8}) - (defn membership-info-container [] {:flex-direction :row diff --git a/src/quo/components/counter/step/style.cljs b/src/quo/components/counter/step/style.cljs index 985cdae4d315..53661a19b84d 100644 --- a/src/quo/components/counter/step/style.cljs +++ b/src/quo/components/counter/step/style.cljs @@ -15,6 +15,7 @@ (colors/theme-colors colors/neutral-20 colors/neutral-80 theme))) (defn active-background-color [customization-color] (colors/custom-color customization-color 50 10)) + (defn complete-background-color [customization-color] (colors/custom-color customization-color 50)) (defn container diff --git a/src/quo/components/dividers/strength_divider/view.cljs b/src/quo/components/dividers/strength_divider/view.cljs index f18c1fccf623..d50404d50b80 100644 --- a/src/quo/components/dividers/strength_divider/view.cljs +++ b/src/quo/components/dividers/strength_divider/view.cljs @@ -9,6 +9,7 @@ [react-native.svg :as svg] [utils.i18n :as i18n])) + (def strength-divider-types {:very-weak {:default-text (i18n/label :t/strength-divider-very-weak-label) :color colors/danger-60 diff --git a/src/quo/components/drawers/drawer_top/style.cljs b/src/quo/components/drawers/drawer_top/style.cljs index 3a7a03a9232d..d225532c5995 100644 --- a/src/quo/components/drawers/drawer_top/style.cljs +++ b/src/quo/components/drawers/drawer_top/style.cljs @@ -21,10 +21,6 @@ {:margin-right 8 :justify-content :center}) -(defn network-text-color - [network] - {:color (colors/custom-color network)}) - (def row {:flex-direction :row :align-items :center}) diff --git a/src/quo/components/dropdowns/dropdown_input/style.cljs b/src/quo/components/dropdowns/dropdown_input/style.cljs index 14fe9132d0d7..1a1dc661bcf2 100644 --- a/src/quo/components/dropdowns/dropdown_input/style.cljs +++ b/src/quo/components/dropdowns/dropdown_input/style.cljs @@ -4,13 +4,6 @@ (def gap 8) -(def blur-view - {:position :absolute - :top 0 - :left 0 - :right 0 - :bottom 0}) - (def left-icon {:margin-right gap}) diff --git a/src/quo/components/graph/wallet_graph/style.cljs b/src/quo/components/graph/wallet_graph/style.cljs index e777a79908dd..6f328a406fac 100644 --- a/src/quo/components/graph/wallet_graph/style.cljs +++ b/src/quo/components/graph/wallet_graph/style.cljs @@ -1,6 +1,4 @@ -(ns quo.components.graph.wallet-graph.style - (:require - [quo.foundations.colors :as colors])) +(ns quo.components.graph.wallet-graph.style) (def gradient-background {:height 294 @@ -14,12 +12,6 @@ :padding-top -10 :height 0}) -(def illustration - {:height 96 - :background-color colors/danger-50 - :align-items :center - :justify-content :center}) - (def empty-state {:width 375 :height 116}) diff --git a/src/quo/components/header.cljs b/src/quo/components/header.cljs deleted file mode 100644 index 2696e44c6796..000000000000 --- a/src/quo/components/header.cljs +++ /dev/null @@ -1,208 +0,0 @@ -(ns quo.components.header - (:require - [oops.core :refer [oget]] - [quo.components.buttons.button.view :as button] - [quo.components.markdown.text :as text] - [quo.foundations.colors :as colors] - [quo.theme :as quo.theme] - [react-native.core :as rn] - [react-native.reanimated :as reanimated])) - -(def header-height 56) - -(defn header-wrapper-style - [{:keys [height border-bottom background theme]}] - (merge - {:background-color (colors/theme-colors - colors/neutral-5 - colors/neutral-95 - theme) - :height height} - (when background - {:background-color background}) - (when border-bottom - {:border-bottom-width 1 - :border-bottom-color (colors/theme-colors - colors/neutral-5 - colors/neutral-95 - theme)}))) - -(def absolute-fill - {:position :absolute - :top 0 - :bottom 0 - :left 0 - :right 0}) - -(def content - {:flex 1 - :flex-direction :row - :align-items :center - :justify-content :center}) - -(def left-style - {:position :absolute - :left 0 - :top 0 - :bottom 0 - :justify-content :center - :align-items :flex-start}) - -(def right-style - {:position :absolute - :right 0 - :top 0 - :bottom 0 - :justify-content :center - :align-items :flex-end}) - -(defn get-title-style - [{:keys [left right]} title-align] - (merge - absolute-fill - (case title-align - :left {:left (:width left) - :right (:width right)} - {:align-items :center - :justify-content :center - :left (max (:width left) (:width right)) - :right (max (:width left) (:width right))}))) - -(def header-actions-style - {:flex 1 - :flex-direction :row - :align-items :center - :justify-content :center - :padding-horizontal 4}) - -(def header-action-placeholder - {:width 16}) - -(def element - {:align-items :center - :justify-content :center - :flex 1}) - -(defn header-action - [{:keys [icon label on-press disabled accessibility-label]}] - [button/button - {:on-press on-press - :disabled? disabled - :icon-only? (boolean icon) - :accessibility-label accessibility-label} - (cond - icon icon - label label)]) - -(defn header-actions - [{:keys [accessories component]}] - [rn/view {:style element} - (cond - (seq accessories) - (into [rn/view {:style header-actions-style}] - (map header-action accessories)) - - component component - - :else - [rn/view {:style header-action-placeholder}])]) - -(defn header-title - [{:keys [title subtitle component title-align]}] - [:<> - (cond - component component - - (and title subtitle) - [:<> - [text/text - {:weight :medium - :number-of-lines 1} - title] - [text/text - {:weight :regular - :color :secondary - :number-of-lines 1} - subtitle]] - - title [text/text - {:weight :bold - :number-of-lines 0 - :align title-align - :size :large} - title])]) - -(defn header - [{:keys [left-accessories left-component border-bottom left-width right-width - right-accessories right-component insets get-layout - title subtitle title-component style title-align - background] - :or {title-align :center - border-bottom false}}] - (let [theme (quo.theme/use-theme) - [layout set-layout] (rn/use-state {:left {:width (or left-width 8) - :height header-height} - :right {:width (or right-width 8) - :height header-height} - :title {:width 0 - :height header-height}}) - handle-layout (rn/use-callback - (fn [el get-layout] - (fn [evt] - (let [width (oget evt "nativeEvent" "layout" "width") - height (oget evt "nativeEvent" "layout" "height")] - (when get-layout - (get-layout el - {:width width - :height height})) - (set-layout - (assoc layout - el - {:width width - :height height}))))) - [layout]) - status-bar-height (get insets :top 0) - height (+ header-height status-bar-height) - title-style (rn/use-memo (fn [] (get-title-style layout title-align)) - [layout title-align])] - [reanimated/view - {:style (header-wrapper-style {:height height - :background background - :border-bottom border-bottom - :theme theme})} - [rn/view - {:pointer-events :box-none - :height status-bar-height}] - [rn/view - {:style (merge {:height header-height} - style) - :pointer-events :box-none} - [rn/view - {:style absolute-fill - :pointer-events :box-none} - [rn/view - {:style content - :pointer-events :box-none} - [rn/view - {:style left-style - :on-layout (handle-layout :left get-layout) - :pointer-events :box-none} - [header-actions - {:accessories left-accessories - :component left-component}]] - [rn/view - {:style title-style - :on-layout (handle-layout :title get-layout) - :pointer-events :box-none} - [header-title - {:title title - :subtitle subtitle - :title-align title-align - :component title-component}]] - [rn/view - {:style right-style - :on-layout (handle-layout :right get-layout) - :pointer-events :box-none} - [header-actions - {:accessories right-accessories - :component right-component}]]]]]])) diff --git a/src/quo/components/list_items/account/style.cljs b/src/quo/components/list_items/account/style.cljs index d94e1badc021..d04fe32ad772 100644 --- a/src/quo/components/list_items/account/style.cljs +++ b/src/quo/components/list_items/account/style.cljs @@ -67,13 +67,6 @@ :height 22 :align-items :center}) -(defn account-address - [blur? theme] - {:height 18 - :color (if blur? - colors/white-opa-40 - (colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}) - (def title-icon-container {:margin-left 4}) diff --git a/src/quo/components/list_items/missing_keypair/style.cljs b/src/quo/components/list_items/missing_keypair/style.cljs index edc34857c94e..d4925ad7e7aa 100644 --- a/src/quo/components/list_items/missing_keypair/style.cljs +++ b/src/quo/components/list_items/missing_keypair/style.cljs @@ -21,16 +21,6 @@ colors/neutral-80-opa-40 theme))}) -(defn icon-container - [{:keys [blur? theme]}] - {:border-radius 32 - :border-width 1 - :border-color (if blur? - colors/white-opa-5 - (colors/theme-colors colors/neutral-20 - colors/neutral-80 - theme))}) - (def name-container {:flex 1 :padding-right 16 diff --git a/src/quo/components/loaders/skeleton.cljs b/src/quo/components/loaders/skeleton.cljs deleted file mode 100644 index cb403af7d703..000000000000 --- a/src/quo/components/loaders/skeleton.cljs +++ /dev/null @@ -1,93 +0,0 @@ -(ns quo.components.loaders.skeleton - (:require - [quo.foundations.colors :as colors] - [quo.theme :as quo.theme] - [react-native.core :as rn] - [react-native.masked-view :as masked-view] - [react-native.reanimated :as reanimated] - [reagent.core :as reagent])) - -(def message-skeleton-height 54) - -(def avatar-skeleton-size 32) - -(def message-content-width - [{:author 80 - :message 249} - {:author 124 - :message 156} - {:author 96 - :message 212} - {:author 112 - :message 144}]) - -;; Standlone message skeleton -(defn- f-message-skeleton - {:deprecated "quo.components.loaders.skeleton-list.view should be used instead"} - [{:keys [theme]}] - - (let [color (colors/theme-colors colors/neutral-5 colors/neutral-70 theme) - loading-color (colors/theme-colors colors/neutral-10 colors/neutral-60 theme) - content-width (rand-nth message-content-width) - author-width (content-width :author) - message-width (content-width :message) - {window-width :width} (rn/get-window) - translate-x (reanimated/use-shared-value (- window-width)) - animated-gradient-style (reanimated/apply-animations-to-style - {:transform [{:translateX translate-x}]} - {:width window-width - :height "100%"})] - (reanimated/animate-shared-value-with-repeat translate-x window-width 1000 :linear (- 1) false) - [masked-view/masked-view - {:style {:height message-skeleton-height} - :maskElement (reagent/as-element - [rn/view - {:style {:height message-skeleton-height - :flex-direction :row - :padding-vertical 11 - :background-color :transparent - :padding-left 21}} - [rn/view - {:style {:height avatar-skeleton-size - :width avatar-skeleton-size - :border-radius (/ avatar-skeleton-size 2) - :background-color color - :overflow :hidden}}] - [rn/view - {:style {:padding-left 8 - :background-color :transparent}} - [rn/view - {:style {:height 8 - :width author-width - :border-radius 6 - :background-color color - :margin-bottom 8 - :overflow :hidden}}] - [rn/view - {:style {:height 16 - :width message-width - :border-radius 6 - :overflow :hidden - :background-color color}}]]])} - [rn/view - {:style {:flex 1 - :background-color color}} - [reanimated/linear-gradient - {:colors [color color loading-color color color] - :start {:x 0 :y 0} - :end {:x 1 :y 0} - :style animated-gradient-style}]]])) - -(defn view - [{:keys [parent-height]}] - (let [theme (quo.theme/use-theme) - number-of-skeletons (int (Math/floor (/ parent-height message-skeleton-height)))] - [rn/view - {:style {:background-color (colors/theme-colors - colors/white - colors/neutral-90 - theme) - :flex 1}} - (doall - (for [n (range number-of-skeletons)] - [:f> f-message-skeleton {:key n :theme theme}]))])) diff --git a/src/quo/components/markdown/list/style.cljs b/src/quo/components/markdown/list/style.cljs index 132517fe1723..0df496c2ab95 100644 --- a/src/quo/components/markdown/list/style.cljs +++ b/src/quo/components/markdown/list/style.cljs @@ -9,8 +9,5 @@ :align-items :flex-start} container-style)) -(def index - {:margin-left 5}) - (def text-container {:margin-left 8}) diff --git a/src/quo/components/messages/gap.cljs b/src/quo/components/messages/gap.cljs index f7d8f5139257..80139c05b94b 100644 --- a/src/quo/components/messages/gap.cljs +++ b/src/quo/components/messages/gap.cljs @@ -123,7 +123,6 @@ :margin-right 2} [timestamp timestamp-far] (when on-info-button-pressed [info-button on-info-button-pressed])] - [rn/touchable-without-feedback {:style {:flex 1 :margin-top 16 :margin-bottom 20} :on-press #(when on-press (on-press))} diff --git a/src/quo/components/selectors/reaction_resource.clj b/src/quo/components/selectors/reaction_resource.clj deleted file mode 100644 index e4356f6a736d..000000000000 --- a/src/quo/components/selectors/reaction_resource.clj +++ /dev/null @@ -1,31 +0,0 @@ -(ns quo.components.selectors.reaction-resource - (:require - [clojure.java.io :as io] - [clojure.string :as string])) - -(def ^:private reactions-dir "./resources/images/reactions/") - -(defn- resolve-reaction - [reaction] - (let [path (str reactions-dir (name reaction) ".png") - file (io/file path)] - (when (.exists file) - `(js/require ~(str "." path))))) - -(defn- find-all-image-base-names - [] - (let [dir (io/file reactions-dir)] - (->> dir - file-seq - (filter #(string/ends-with? % "png")) - (map #(.getName %)) - (map #(string/replace % #"\.png$" "")) - (map #(first (string/split % #"@"))) - distinct))) - -(defmacro resolve-all-reactions - [] - (reduce (fn [acc reaction] - (assoc acc reaction (resolve-reaction reaction))) - {} - (find-all-image-base-names))) diff --git a/src/quo/components/selectors/reaction_resource.cljs b/src/quo/components/selectors/reaction_resource.cljs index d019c3d8701e..f4e2c3370d2a 100644 --- a/src/quo/components/selectors/reaction_resource.cljs +++ b/src/quo/components/selectors/reaction_resource.cljs @@ -1,8 +1,4 @@ -(ns quo.components.selectors.reaction-resource - (:require-macros [quo.components.selectors.reaction-resource :refer [resolve-all-reactions]])) - -(def ^:private reactions - (resolve-all-reactions)) +(ns quo.components.selectors.reaction-resource) (def system-emojis {:reaction/thumbs-up "👍" @@ -12,9 +8,3 @@ :reaction/sad "😢" :reaction/angry "😡"}) -(defn get-reaction - [reaction] - (assert (keyword? reaction) "Reaction should be a keyword") - (assert (= "reaction" (namespace reaction)) - "Reaction keyword should be namespaced with :reaction") - (get reactions (name reaction))) diff --git a/src/quo/components/settings/category/style.cljs b/src/quo/components/settings/category/style.cljs index ee59a5f51b7e..002acc9af5f1 100644 --- a/src/quo/components/settings/category/style.cljs +++ b/src/quo/components/settings/category/style.cljs @@ -44,19 +44,3 @@ :background-color (if blur? :transparent (colors/theme-colors colors/neutral-5 colors/neutral-95 theme))}) - -(defn blur-container - [] - {:position :absolute - :left 0 - :right 0 - :bottom 0 - :top 0 - :overflow :hidden}) - -(defn blur-view - [theme] - {:style {:flex 1} - :blur-radius 10 - :blur-type theme - :blur-amount 20}) diff --git a/src/quo/components/settings/reorder_item/style.cljs b/src/quo/components/settings/reorder_item/style.cljs index 308d85d6a114..e6422b9a59f8 100644 --- a/src/quo/components/settings/reorder_item/style.cljs +++ b/src/quo/components/settings/reorder_item/style.cljs @@ -141,9 +141,6 @@ :width 19 :margin-right 3}) -(def tab-item-label - {:font-size 14}) - (defn tab-icon [theme] {:height 16 diff --git a/src/quo/components/tags/context_tag/style.cljs b/src/quo/components/tags/context_tag/style.cljs index eed0e684ff2b..8ee8e73de91e 100644 --- a/src/quo/components/tags/context_tag/style.cljs +++ b/src/quo/components/tags/context_tag/style.cljs @@ -117,8 +117,3 @@ (if (= size 24) {:margin-left 4} {:margin-left 2})) - -(def audio - {:margin-right 6 - :flex-direction :row - :align-items :center}) diff --git a/src/quo/components/wallet/token_input/style.cljs b/src/quo/components/wallet/token_input/style.cljs index ca79e504df48..a9fdacf57441 100644 --- a/src/quo/components/wallet/token_input/style.cljs +++ b/src/quo/components/wallet/token_input/style.cljs @@ -19,10 +19,6 @@ {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme) :padding-bottom 3}) -(def text-input-container - {:flex-direction :row - :align-items :flex-end}) - (defn input-container [window-width] {:width (- window-width 120) diff --git a/src/quo/core.cljs b/src/quo/core.cljs index 50a057b8fc64..401956939011 100644 --- a/src/quo/core.cljs +++ b/src/quo/core.cljs @@ -67,7 +67,6 @@ quo.components.gradient.gradient-cover.view quo.components.graph.interactive-graph.view quo.components.graph.wallet-graph.view - quo.components.header quo.components.icon quo.components.info.info-message.view quo.components.info.information-box.view @@ -254,13 +253,9 @@ (def community-token-gating quo.components.community.community-token-gating.view/view) (def communities-membership-list-item quo.components.community.community-list-view/communities-membership-list-item) -(def community-stats-column quo.components.community.community-view/community-stats-column) (def community-stat quo.components.community.community-stat.view/view) (def community-tags quo.components.community.community-view/community-tags) -(def community-title quo.components.community.community-view/community-title) -(def permission-tag-container quo.components.community.community-view/permission-tag-container) (def discover-card quo.components.community.banner.view/view) -(def community-icon quo.components.community.icon/community-icon) (def channel-action quo.components.community.channel-action.view/view) (def channel-actions quo.components.community.channel-actions.view/view) @@ -298,7 +293,6 @@ (def wallet-graph quo.components.graph.wallet-graph.view/view) ;;;; Header -(def header quo.components.header/header) (def animated-header-list quo.components.animated-header-flatlist.view/animated-header-list) ;;;; Gradient @@ -377,8 +371,6 @@ ;;;; Notifications (def activity-log quo.components.notifications.activity-log.view/view) (def activity-logs-photos quo.components.notifications.activity-logs-photos.view/view) -(def notification-dot quo.components.common.notification-dot.view/view) -(def count-down-circle quo.components.notifications.count-down-circle/circle-timer) (def notification quo.components.notifications.notification.view/notification) (def toast quo.components.notifications.toast.view/toast) @@ -455,9 +447,6 @@ quo.components.text-combinations.view/view) (def username quo.components.text-combinations.username.view/view) -;;;; Utilities - Outside of design system -(def token quo.components.utilities.token.view/view) - ;;;; Wallet (def account-card quo.components.wallet.account-card.view/view) (def account-origin quo.components.wallet.account-origin.view/view) diff --git a/src/react_native/audio_toolkit.cljs b/src/react_native/audio_toolkit.cljs index 6ac8881c13ef..c0d791e064a1 100644 --- a/src/react_native/audio_toolkit.cljs +++ b/src/react_native/audio_toolkit.cljs @@ -7,11 +7,8 @@ (def PLAYING (.-PLAYING ^js MediaStates)) (def PAUSED (.-PAUSED ^js MediaStates)) (def RECORDING (.-RECORDING ^js MediaStates)) -(def PREPARED (.-PREPARED ^js MediaStates)) (def IDLE (.-IDLE ^js MediaStates)) -(def ERROR (.-ERROR ^js MediaStates)) (def DESTROYED (.-DESTROYED ^js MediaStates)) -(def SEEKING (.-SEEKING ^js MediaStates)) ;; get PlaybackCategories from react module (def PLAYBACK (.-Playback ^js PlaybackCategories)) @@ -59,15 +56,6 @@ (on-error {:error (.-err err) :message (.-message err)}) (on-prepared)))))) -(defn prepare-recorder - [recorder on-prepared on-error] - (when (and recorder (.-canPrepare ^js recorder)) - (.prepare ^js recorder - (fn [^js err] - (if err - (on-error {:error (.-err err) :message (.-message err)}) - (on-prepared)))))) - (defn start-recording [recorder on-start on-error] (when (and recorder @@ -90,24 +78,6 @@ (on-stop)))) (on-stop))) -(defn pause-recording - [recorder on-pause on-error] - (when (and recorder (.-isRecording ^js recorder)) - (.pause ^js recorder - (fn [^js err] - (if err - (on-error {:error (.-err err) :message (.-message err)}) - (on-pause)))))) - -(defn start-playing - [player on-start on-error] - (when (and player (.-canPlay ^js player)) - (.play ^js player - (fn [^js err] - (if err - (on-error {:error (.-err err) :message (.-message err)}) - (on-start)))))) - (defn stop-playing [player on-stop on-error] (if (and player (.-isPlaying ^js player)) diff --git a/src/react_native/background_timer.cljs b/src/react_native/background_timer.cljs index c5af269229a0..736d1d9a7ab8 100644 --- a/src/react_native/background_timer.cljs +++ b/src/react_native/background_timer.cljs @@ -9,11 +9,3 @@ (defn clear-timeout [id] (.clearTimeout background-timer id)) - -(defn set-interval - [cb ms] - (.setInterval background-timer cb ms)) - -(defn clear-interval - [id] - (.clearInterval background-timer id)) diff --git a/src/react_native/core.cljs b/src/react_native/core.cljs index 33aef6ed54fc..694e2f2a67b2 100644 --- a/src/react_native/core.cljs +++ b/src/react_native/core.cljs @@ -2,7 +2,6 @@ (:require ["react" :as react] ["react-native" :as react-native] - [oops.core :as oops] [promesa.core :as promesa] [react-native.flat-list :as flat-list] [react-native.platform :as platform] @@ -81,8 +80,6 @@ (def dismiss-keyboard! #(.dismiss keyboard)) -(def device-event-emitter (.-DeviceEventEmitter ^js react-native)) - (defn hide-splash-screen [] (.hide ^js (-> react-native .-NativeModules .-SplashScreen))) @@ -136,16 +133,8 @@ (def use-state react/useState) -(def create-ref react/createRef) - (def use-ref react/useRef) -(defn current-ref - [ref] - (oops/oget ref "current")) - -(def create-context react/createContext) - (def use-context react/useContext) (defn use-ref-atom @@ -172,8 +161,6 @@ js/undefined)) (defn use-effect - {:deprecated - "use-mount or use-unmount should be used, more here https://github.com/status-im/status-mobile/blob/develop/doc/ui-guidelines.md#effects"} ([handler] (use-effect handler nil)) ([handler deps] @@ -216,22 +203,11 @@ :linear (-> ^js layout-animation .-Presets .-linear) :spring (-> ^js layout-animation .-Presets .-spring)}) -(def find-node-handle (.-findNodeHandle ^js react-native)) - (defn selectable-text-input-manager [] (when (exists? (.-NativeModules ^js react-native)) (.-RNSelectableTextInputManager ^js (.-NativeModules ^js react-native)))) -;; TODO: iOS native implementation https://github.com/status-im/status-mobile/issues/14137 -(defonce selectable-text-input - (if platform/android? - (reagent/adapt-react-class - (.requireNativeComponent ^js react-native "RNSelectableTextInput")) - view)) - (def linking (.-Linking react-native)) (defn open-url [link] (.openURL ^js linking link)) - -(def set-status-bar-style react-native/StatusBar.setBarStyle) diff --git a/src/react_native/gesture.cljs b/src/react_native/gesture.cljs index e4c6578476a2..b7e0a4da8fb8 100644 --- a/src/react_native/gesture.cljs +++ b/src/react_native/gesture.cljs @@ -39,10 +39,6 @@ (defn min-distance [gesture dist] (.minDistance ^js gesture dist)) -(defn fail-offset-x [gesture offset] (.failOffsetX ^js gesture offset)) - -(defn hit-slop [gesture settings] (.hitSlop ^js gesture settings)) - (defn number-of-taps [gesture amount] (.numberOfTaps ^js gesture amount)) (defn enabled [gesture enabled?] (.enabled ^js gesture enabled?)) diff --git a/src/react_native/navigation.cljs b/src/react_native/navigation.cljs index 55ed10a5dee4..433fffa4b5a6 100644 --- a/src/react_native/navigation.cljs +++ b/src/react_native/navigation.cljs @@ -14,10 +14,6 @@ [root] (.setRoot ^js Navigation (clj->js root))) -(defn set-stack-root - [stack component] - (.setStackRoot ^js Navigation stack (clj->js component))) - (defn push [arg1 arg2] (.push ^js Navigation arg1 (clj->js arg2))) @@ -65,20 +61,6 @@ [handler] (.registerModalDismissedListener ^js (.events ^js Navigation) handler)) -(defn reg-component-did-appear-listener - [handler] - (.registerComponentDidAppearListener - ^js (.events ^js Navigation) - (fn [^js evn] - (handler (keyword (.-componentName evn)))))) - -(defn reg-component-did-disappear-listener - [handler] - (.registerComponentDidDisappearListener - ^js (.events ^js Navigation) - (fn [^js evn] - (handler (.-componentName evn))))) - (defn merge-options [id opts] (.mergeOptions Navigation id (clj->js opts))) @@ -95,7 +77,4 @@ :bottom-tabs-height (.-bottomTabsHeight consts) :status-bar-height (.-statusBarHeight consts)}))) -(defn bind-component - [^js/Object this component-id] - (set! (. this -navigationEventListener) - (.. Navigation events (bindComponent this component-id)))) + diff --git a/src/react_native/permissions.cljs b/src/react_native/permissions.cljs index 6c097e8af95c..5299fa49e6f9 100644 --- a/src/react_native/permissions.cljs +++ b/src/react_native/permissions.cljs @@ -1,8 +1,7 @@ (ns react-native.permissions (:require ["react-native-permissions" :refer - [check openSettings PERMISSIONS requestMultiple requestNotifications - RESULTS]] + [check PERMISSIONS requestMultiple requestNotifications RESULTS]] [react-native.platform :as platform] [taoensso.timbre :as log])) @@ -47,8 +46,6 @@ (.then #(on-result (not (#{(.-BLOCKED RESULTS) (.-DENIED RESULTS)} %)))) (.catch #(on-error %)))) -(def open-settings openSettings) - (defn request-notifications "`notification-options` is only used on iOS. A map with `:status` and `settings` (only for iOS) is passed to the callbacks. diff --git a/src/react_native/reanimated.cljs b/src/react_native/reanimated.cljs index 464b7f3e574c..0d6967e5fb28 100644 --- a/src/react_native/reanimated.cljs +++ b/src/react_native/reanimated.cljs @@ -13,14 +13,11 @@ withSequence withDecay Easing - Keyframe cancelAnimation SlideInUp SlideOutUp LinearTransition - enableLayoutAnimations - useAnimatedScrollHandler - runOnJS)] + useAnimatedScrollHandler)] ["react-native-redash" :refer (withPause)] [react-native.flat-list :as rn-flat-list] [react-native.platform :as platform] @@ -29,8 +26,6 @@ [utils.transforms :as transforms] [utils.worklets.core :as worklets.core])) -(def enable-layout-animations enableLayoutAnimations) - (def ^:const default-duration 300) ;; Animations @@ -49,7 +44,6 @@ updated-props (update reagent-props :style transforms/styles-with-vectors)] (into [view* updated-props] children))) -(def text (reagent/adapt-react-class (.-Text reanimated))) (def scroll-view (reagent/adapt-react-class (.-ScrollView reanimated))) (def image (reagent/adapt-react-class (.-Image reanimated))) @@ -73,13 +67,11 @@ (def with-delay withDelay) (def with-spring withSpring) (def with-decay withDecay) -(def key-frame Keyframe) (def with-repeat withRepeat) (def with-sequence withSequence) (def with-pause withPause) (def cancel-animation cancelAnimation) -(def run-on-js runOnJS) ;; Easings (def bezier (.-bezier ^js Easing)) @@ -195,8 +187,3 @@ (clj->js {:duration duration :easing (default-easing)}))))) -(defn with-timing-duration - [v duration] - (with-timing v - (clj->js {:duration duration - :easing (in-out (.-quad ^js Easing))}))) diff --git a/src/react_native/svg.cljs b/src/react_native/svg.cljs index e9397c2d873b..9bdbac0d0067 100644 --- a/src/react_native/svg.cljs +++ b/src/react_native/svg.cljs @@ -10,7 +10,5 @@ (def defs (reagent/adapt-react-class Svg/Defs)) (def circle (reagent/adapt-react-class Svg/Circle)) (def svg-xml (reagent/adapt-react-class Svg/SvgXml)) -(def svg-uri (reagent/adapt-react-class Svg/SvgUri)) -(def g (reagent/adapt-react-class Svg/G)) (def linear-gradient (reagent/adapt-react-class Svg/LinearGradient)) (def stop (reagent/adapt-react-class Svg/Stop)) diff --git a/src/react_native/wallet_connect.cljs b/src/react_native/wallet_connect.cljs index bfc5608446be..609a23823dbb 100644 --- a/src/react_native/wallet_connect.cljs +++ b/src/react_native/wallet_connect.cljs @@ -80,10 +80,6 @@ "core.pairing.pair" (bean/->js {:uri url}))) -(defn get-pairings - [web3-wallet] - (oops/ocall web3-wallet "core.pairing.getPairings")) - (defn register-handler [{:keys [web3-wallet event handler]}] (oops/ocall web3-wallet diff --git a/src/status_im/common/alert_banner/style.cljs b/src/status_im/common/alert_banner/style.cljs index 3594d37dcc62..acbbbde4cc0b 100644 --- a/src/status_im/common/alert_banner/style.cljs +++ b/src/status_im/common/alert_banner/style.cljs @@ -2,10 +2,6 @@ (def border-radius 20) -(defn container - [background-color] - {:background-color background-color}) - (def second-banner-wrapper {:margin-top (- border-radius) :overflow :hidden diff --git a/src/status_im/common/bottom_sheet/style.cljs b/src/status_im/common/bottom_sheet/style.cljs index ca83a1fb04b3..dda8182ccf83 100644 --- a/src/status_im/common/bottom_sheet/style.cljs +++ b/src/status_im/common/bottom_sheet/style.cljs @@ -15,12 +15,6 @@ :border-top-left-radius sheet-border-radius :border-top-right-radius sheet-border-radius}) -(def gradient-bg - {:position :absolute - :top 0 - :left 0 - :right 0}) - (def shell-bg {:background-color colors/bottom-sheet-background-blur :flex 1}) diff --git a/src/status_im/common/home/actions/view.cljs b/src/status_im/common/home/actions/view.cljs index 251a711b4658..1a2bd6e03bc2 100644 --- a/src/status_im/common/home/actions/view.cljs +++ b/src/status_im/common/home/actions/view.cljs @@ -266,16 +266,6 @@ :chevron? false})) ;; TODO(OmarBasem): Requires design input. -(defn rename-entry - [] - (entry {:icon :i/edit - :label (i18n/label :t/rename) - :on-press #(js/alert "TODO: to be implemented, requires design input") - :danger? false - :accessibility-label :rename-contact - :sub-label nil - :chevron? false})) - (defn show-qr-entry [public-key] (entry {:icon :i/qr-code diff --git a/src/status_im/common/keychain/events.cljs b/src/status_im/common/keychain/events.cljs index 4e4a9095b221..8475c4b255cc 100644 --- a/src/status_im/common/keychain/events.cljs +++ b/src/status_im/common/keychain/events.cljs @@ -44,7 +44,6 @@ (callback false))) (def auth-method-biometric "biometric") -(def auth-method-biometric-prepare "biometric-prepare") (def auth-method-none "none") (defn save-auth-method! diff --git a/src/status_im/common/lightbox/text_sheet/style.cljs b/src/status_im/common/lightbox/text_sheet/style.cljs index 83de40364c8d..5999742d2a7b 100644 --- a/src/status_im/common/lightbox/text_sheet/style.cljs +++ b/src/status_im/common/lightbox/text_sheet/style.cljs @@ -13,13 +13,6 @@ :left 0 :right 0})) -(defn text-style - [expandable-text?] - {:color colors/white - :margin-horizontal 20 - :align-items (when-not expandable-text? :center) - :flex-grow 1}) - (def bar-container {:height constants/bar-container-height :left 0 diff --git a/src/status_im/common/lightbox/zoomable_image/constants.cljs b/src/status_im/common/lightbox/zoomable_image/constants.cljs index d22d8d413173..8e7b99531990 100644 --- a/src/status_im/common/lightbox/zoomable_image/constants.cljs +++ b/src/status_im/common/lightbox/zoomable_image/constants.cljs @@ -14,6 +14,4 @@ (def ^:const default-duration 300) -(def ^:const default-dimension 1000) - (def ^:const margin 16) diff --git a/src/status_im/common/new_device_sheet/style.cljs b/src/status_im/common/new_device_sheet/style.cljs index 9d71a9df0660..1ccdca33ce8d 100644 --- a/src/status_im/common/new_device_sheet/style.cljs +++ b/src/status_im/common/new_device_sheet/style.cljs @@ -1,5 +1,4 @@ -(ns status-im.common.new-device-sheet.style - (:require [quo.foundations.colors :as colors])) +(ns status-im.common.new-device-sheet.style) (def heading {:padding-left 20 @@ -8,16 +7,3 @@ (def message {:padding-horizontal 20 :padding-top 4}) - -(def warning - {:margin-horizontal 20 - :margin-top 10}) - -(def drawer-container - {:padding-horizontal 13 - :padding-top 16}) - -(def settings-subtext - {:color colors/white-opa-70 - :align-self :center - :margin-bottom 12}) diff --git a/src/status_im/common/pairing/events.cljs b/src/status_im/common/pairing/events.cljs index 10fb28476016..a8e269fcb4f8 100644 --- a/src/status_im/common/pairing/events.cljs +++ b/src/status_im/common/pairing/events.cljs @@ -17,8 +17,8 @@ constants/local-pairing-event-connection-success) (= action constants/local-pairing-action-connect)) - connection-error? (and (= type - constants/local-pairing-event-connection-error)) + connection-error? (= type + constants/local-pairing-event-connection-error) error-on-pairing? (contains? constants/local-pairing-event-errors type) completed-pairing? (and (= type constants/local-pairing-event-transfer-success) diff --git a/src/status_im/common/password_authentication/events.cljs b/src/status_im/common/password_authentication/events.cljs deleted file mode 100644 index bb5f6c976a7e..000000000000 --- a/src/status_im/common/password_authentication/events.cljs +++ /dev/null @@ -1,13 +0,0 @@ -(ns status-im.common.password-authentication.events - (:require - [status-im.navigation.events :as navigation] - [utils.re-frame :as rf])) - -(rf/defn close - {:events [:password-authentication/show]} - [{:keys [db]} content button] - (rf/merge {:db (assoc db - :password-authentication - {:error nil - :button button})} - (navigation/show-bottom-sheet content))) diff --git a/src/status_im/common/password_authentication/view.cljs b/src/status_im/common/password_authentication/view.cljs deleted file mode 100644 index d80083673249..000000000000 --- a/src/status_im/common/password_authentication/view.cljs +++ /dev/null @@ -1,42 +0,0 @@ -(ns status-im.common.password-authentication.view - (:require - [native-module.core :as native-module] - [quo.core :as quo] - [react-native.core :as rn] - [reagent.core :as reagent] - [status-im.contexts.profile.utils :as profile.utils] - [utils.i18n :as i18n] - [utils.re-frame :as rf])) - -(defn view - [] - (let [entered-password (reagent/atom "")] - (fn [] - (let [profile (rf/sub [:profile/profile-with-image]) - {:keys [error button]} (rf/sub [:password-authentication])] - [rn/view {:padding-horizontal 20} - [quo/text {:size :heading-1 :weight :semi-bold} - (i18n/label :t/enter-password)] - [rn/view {:style {:margin-top 8 :margin-bottom 20}} - [quo/context-tag - {:size 24 - :full-name (profile.utils/displayed-name profile) - :profile-picture (profile.utils/photo profile)}]] - [quo/input - {:type :password - :label (i18n/label :t/profile-password) - :placeholder (i18n/label :t/type-your-password) - :error? (when (not-empty error) error) - :auto-focus true - :on-change-text #(reset! entered-password %)}] - (when (not-empty error) - [quo/info-message - {:status :error - :size :default - :icon :i/info - :container-style {:margin-top 8}} - (i18n/label :t/oops-wrong-password)]) - [quo/button - {:container-style {:margin-bottom 12 :margin-top 40} - :on-press #((:on-press button) (native-module/sha3 @entered-password))} - (:label button)]])))) diff --git a/src/status_im/common/router.cljs b/src/status_im/common/router.cljs index 994bb2107105..1d6e63a95759 100644 --- a/src/status_im/common/router.cljs +++ b/src/status_im/common/router.cljs @@ -26,9 +26,7 @@ (def status-web2-domain "status.app") -(def user-path "u#") (def user-with-data-path "u/") -(def community-path "c#") (def community-with-data-path "c/") (def channel-path "cc/") @@ -244,18 +242,6 @@ (cb {:type :community-chat :error :not-found}))) -(defn match-browser - [uri {:keys [domain]}] - ;; NOTE: We rebuild domain from original URI and matched domain - (let [domain (->> (string/split uri domain) - second - (str domain))] - (if (security/safe-link? domain) - {:type :browser - :url domain} - {:type :browser - :error :unsafe-link}))) - (defn match-browser-string [domain] (if (security/safe-link? domain) diff --git a/src/status_im/common/router_test.cljs b/src/status_im/common/router_test.cljs index 62bee6602496..6b667b2b224e 100644 --- a/src/status_im/common/router_test.cljs +++ b/src/status_im/common/router_test.cljs @@ -7,7 +7,6 @@ "0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073") (def chat-id "59eb36e6-9d4d-4724-9d3a-8a3cdc5e8a8e-0x04f383daedc92a66add4c90d8884004ef826cba113183a0052703c8c77fed1522f88f44550498d20679af98907627059a295e43212a1cd3c1f21a157704d608c13") -(def chat-name-url "Test%20group%20chat") (def chat-name "Test group chat") (deftest parse-uris-test diff --git a/src/status_im/common/scan_qr_code/style.cljs b/src/status_im/common/scan_qr_code/style.cljs index 1fc3bde2d005..1db24064021b 100644 --- a/src/status_im/common/scan_qr_code/style.cljs +++ b/src/status_im/common/scan_qr_code/style.cljs @@ -49,10 +49,6 @@ {:padding-horizontal screen-padding :color colors/white}) -(def tabs-container - {:padding-horizontal screen-padding - :margin-top 20}) - (def scan-qr-code-container {:margin-top 20}) diff --git a/src/status_im/common/scroll_page/style.cljs b/src/status_im/common/scroll_page/style.cljs index 0b52cc9da722..d977f5d281dc 100644 --- a/src/status_im/common/scroll_page/style.cljs +++ b/src/status_im/common/scroll_page/style.cljs @@ -4,14 +4,6 @@ [react-native.platform :as platform] [react-native.reanimated :as reanimated])) -(defn image-slider - [size] - {:top -64 - :height size - :width size - :z-index 4 - :flex 1}) - (defn blur-slider [animation height theme] (reanimated/apply-animations-to-style @@ -26,24 +18,6 @@ (colors/theme-colors colors/white colors/neutral-80 theme) :transparent)})) -(defn sticky-header-title - [animation] - (reanimated/apply-animations-to-style - {:opacity animation} - {:position :absolute - :flex-direction :row - :left 64 - :top 16 - :margin-top 44})) - -(def sticky-header-image - {:border-radius 12 - :border-width 0 - :border-color :transparent - :width 24 - :height 24 - :margin-right 8}) - (defn children-container [{:keys [border-radius background-color]}] {:flex 1 diff --git a/src/status_im/common/signals/events.cljs b/src/status_im/common/signals/events.cljs index c1090dd470f1..68f12dbf1022 100644 --- a/src/status_im/common/signals/events.cljs +++ b/src/status_im/common/signals/events.cljs @@ -13,8 +13,7 @@ (rf/defn summary [{:keys [db] :as cofx} peers-summary] - (let [previous-summary (:peers-summary db) - peers-count (count peers-summary)] + (let [peers-count (count peers-summary)] (rf/merge cofx {:db (assoc db :peers-summary peers-summary diff --git a/src/status_im/common/standard_authentication/enter_password/style.cljs b/src/status_im/common/standard_authentication/enter_password/style.cljs index a691bd578816..84133df4b48f 100644 --- a/src/status_im/common/standard_authentication/enter_password/style.cljs +++ b/src/status_im/common/standard_authentication/enter_password/style.cljs @@ -5,11 +5,6 @@ :border-top-left-radius 12 :border-top-right-radius 12}) -(def error-message - {:margin-top 8 - :flex-direction :row - :align-items :center}) - (def enter-password-button {:margin-top 45 :margin-bottom 12}) diff --git a/src/status_im/common/timer/events.cljs b/src/status_im/common/timer/events.cljs deleted file mode 100644 index 18caa871fb70..000000000000 --- a/src/status_im/common/timer/events.cljs +++ /dev/null @@ -1,18 +0,0 @@ -(ns status-im.common.timer.events - (:require - [re-frame.core :as re-frame] - [react-native.background-timer :as background-timer])) - -(re-frame/reg-fx - :background-timer/dispatch-later - (fn [params] - (doseq [{:keys [ms dispatch]} params] - (when (and ms dispatch) - (background-timer/set-timeout #(re-frame/dispatch dispatch) ms))))) - -(re-frame/reg-fx - :background-timer/clear-timeouts - (fn [ids] - (doseq [id ids] - (when id - (background-timer/clear-timeout id))))) diff --git a/src/status_im/common/universal_links.cljs b/src/status_im/common/universal_links.cljs index 35e47849daeb..730b6c5af12f 100644 --- a/src/status_im/common/universal_links.cljs +++ b/src/status_im/common/universal_links.cljs @@ -257,9 +257,3 @@ ;;error "route ip+net: netlinkrib: permission denied" is fixed on status-go side #_(native-module/start-searching-for-local-pairing-peers #(log/info "[local-pairing] errors from local-pairing-preflight-outbound-check ->" %))) - -(defn finalize - "Remove event listener for url" - [] - (log/debug "universal-links: finalizing") - (.removeEventListener ^js rn/linking "url" url-event-listener)) diff --git a/src/status_im/config.cljs b/src/status_im/config.cljs index 86877c589eee..735c75aa59c4 100644 --- a/src/status_im/config.cljs +++ b/src/status_im/config.cljs @@ -50,29 +50,15 @@ (def opensea-api-key OPENSEA_API_KEY) (def status-proxy-enabled? true) (def status-proxy-stage-name (get-config :STATUS_PROXY_STAGE_NAME "test")) -(def bootnodes-settings-enabled? (enabled? (get-config :BOOTNODES_SETTINGS_ENABLED "1"))) -(def mailserver-confirmations-enabled? (enabled? (get-config :MAILSERVER_CONFIRMATIONS_ENABLED))) (def pairing-popup-disabled? (enabled? (get-config :PAIRING_POPUP_DISABLED "0"))) (def cached-webviews-enabled? (enabled? (get-config :CACHED_WEBVIEWS_ENABLED 0))) -(def snoopy-enabled? (enabled? (get-config :SNOOPY 0))) -(def dev-build? (enabled? (get-config :DEV_BUILD 0))) -(def max-message-delivery-attempts (js/parseInt (get-config :MAX_MESSAGE_DELIVERY_ATTEMPTS "6"))) + ;; NOTE: only disabled in releases -(def local-notifications? (enabled? (get-config :LOCAL_NOTIFICATIONS "1"))) (def blank-preview? (enabled? (get-config :BLANK_PREVIEW "1"))) -(def group-chat-enabled? (enabled? (get-config :GROUP_CHATS_ENABLED "0"))) (def tooltip-events? (enabled? (get-config :TOOLTIP_EVENTS "0"))) -(def commands-enabled? (enabled? (get-config :COMMANDS_ENABLED "0"))) -(def keycard-test-menu-enabled? (enabled? (get-config :KEYCARD_TEST_MENU "1"))) -(def qr-test-menu-enabled? (enabled? (get-config :QR_READ_TEST_MENU "0"))) (def quo-preview-enabled? (enabled? (get-config :ENABLE_QUO_PREVIEW "0"))) -(def database-management-enabled? (enabled? (get-config :DATABASE_MANAGEMENT_ENABLED "0"))) (def debug-webview? (enabled? (get-config :DEBUG_WEBVIEW "0"))) -(def test-stateofus? (enabled? (get-config :TEST_STATEOFUS "0"))) (def two-minutes-syncing? (enabled? (get-config :TWO_MINUTES_SYNCING "0"))) -(def swap-enabled? (enabled? (get-config :SWAP_ENABLED "0"))) -(def stickers-test-enabled? (enabled? (get-config :STICKERS_TEST_ENABLED "0"))) -(def local-pairing-mode-enabled? (enabled? (get-config :LOCAL_PAIRING_ENABLED "1"))) (def show-not-implemented-features? (enabled? (get-config :SHOW_NOT_IMPLEMENTED_FEATURES "0"))) ;; CONFIG VALUES @@ -81,8 +67,6 @@ (def fleet (get-config :FLEET "")) (def apn-topic (get-config :APN_TOPIC "im.status.ethereum")) (def max-installations 2) -; currently not supported in status-go -(def enable-remove-profile-picture? false) (defn env-variable->int [env-var-name default-value] @@ -114,16 +98,6 @@ (def fast-create-community-enabled? (enabled? (get-config :FAST_CREATE_COMMUNITY_ENABLED "0"))) -(def waku-nodes-config - {:status.prod - ["enrtree://AL65EKLJAUXKKPG43HVTML5EFFWEZ7L4LOKTLZCLJASG4DSESQZEC@prod.status.nodes.status.im"] - :status.test - ["enrtree://AIO6LUM3IVWCU2KCPBBI6FEH2W42IGK3ASCZHZGG5TIXUR56OGQUO@test.status.nodes.status.im"] - :waku.sandbox - ["enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im"] - :waku.test - ["enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im"]}) - (def community-accounts-selection-enabled? true) (def fetch-messages-enabled? (enabled? (get-config :FETCH_MESSAGES_ENABLED "1"))) (def test-networks-enabled? (enabled? (get-config :TEST_NETWORKS_ENABLED "0"))) diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 625aafce013f..559fa24a57f3 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -8,7 +8,6 @@ (def ^:const content-type-sticker 2) (def ^:const content-type-status 3) (def ^:const content-type-emoji 4) -(def ^:const content-type-command 5) (def ^:const content-type-system-text 6) (def ^:const content-type-image 7) (def ^:const content-type-audio 8) @@ -23,7 +22,6 @@ ;; Not implemented in status-go, only used for testing/ui work (def ^:const content-type-gif 100) -(def ^:const content-type-link 101) (def ^:const content-type-album 102) (def ^:const contact-request-state-none 0) @@ -32,11 +30,9 @@ (def ^:const contact-request-state-received 3) (def ^:const contact-request-state-dismissed 4) -(def ^:const contact-verification-status-unknown 0) (def ^:const contact-verification-status-pending 1) (def ^:const contact-verification-status-accepted 2) (def ^:const contact-verification-status-declined 3) -(def ^:const contact-verification-status-cancelled 4) (def ^:const contact-verification-status-trusted 5) (def ^:const contact-verification-status-untrustworthy 6) @@ -79,7 +75,6 @@ (def ^:const chat-preview-type-community 0) (def ^:const chat-preview-type-non-community 1) -(def ^:const contact-request-message-state-none 0) (def ^:const contact-request-message-state-pending 1) (def ^:const contact-request-message-state-accepted 2) (def ^:const contact-request-message-state-declined 3) @@ -98,27 +93,12 @@ emoji-reaction-sad :reaction/sad emoji-reaction-angry :reaction/angry}) -(def ^:const invitation-state-unknown 0) (def ^:const invitation-state-requested 1) (def ^:const invitation-state-rejected 2) (def ^:const invitation-state-approved 3) -(def ^:const invitation-state-granted 4) -(def ^:const invitation-state-removed 5) - (def ^:const message-type-one-to-one 1) -(def ^:const message-type-public-group 2) -(def ^:const message-type-private-group 3) (def ^:const message-type-private-group-system-message 4) -(def ^:const message-type-community-chat 5) -(def ^:const message-type-gap 6) -(def ^:const command-state-request-address-for-transaction 1) -(def ^:const command-state-request-address-for-transaction-declined 2) -(def ^:const command-state-request-address-for-transaction-accepted 3) -(def ^:const command-state-request-transaction 4) -(def ^:const command-state-request-transaction-declined 5) -(def ^:const command-state-transaction-pending 6) -(def ^:const command-state-transaction-sent 7) (def ^:const profile-default-color :blue) (def ^:const profile-name-max-length 20) @@ -157,33 +137,13 @@ (def ^:const mailserver-password "status-offline-inbox") -(def ^:const send-transaction-failed-parse-response 1) -(def ^:const send-transaction-failed-parse-params 2) -(def ^:const send-transaction-no-account-selected 3) -(def ^:const send-transaction-invalid-tx-sender 4) -(def ^:const send-transaction-err-decrypt 5) - -(def ^:const web3-send-transaction "eth_sendTransaction") -(def ^:const web3-personal-sign "personal_sign") -(def ^:const web3-eth-sign "eth_sign") -(def ^:const web3-sign-typed-data "eth_signTypedData") -(def ^:const web3-sign-typed-data-v3 "eth_signTypedData_v3") -(def ^:const web3-sign-typed-data-v4 "eth_signTypedData_v4") - -(def ^:const web3-keycard-sign-typed-data "keycard_signTypedData") -(def ^:const status-create-address "status_createaddress") - -(def ^:const community-unknown-membership-access 0) (def ^:const community-no-membership-access 1) (def ^:const community-invitation-only-access 2) (def ^:const community-on-request-access 3) -(def ^:const community-token-permission-unknown 0) (def ^:const community-token-permission-become-admin 1) (def ^:const community-token-permission-become-member 2) -(def ^:const community-token-permission-can-view-channel 3) -(def ^:const community-token-permission-can-view-and-post-channel 4) (def ^:const community-token-permission-become-token-master 5) (def ^:const community-token-permission-become-token-owner 6) (def ^:const community-role-permissions @@ -195,21 +155,11 @@ (def ^:const community-token-type-erc20 1) (def ^:const community-token-type-erc721 2) -;; Community rules for joining -(def ^:const community-rule-ens-only "ens-only") - -(def ^:const community-channel-access-no-membership 1) -(def ^:const community-channel-access-invitation-only 2) -(def ^:const community-channel-access-on-request 3) (def ^:const community-request-to-join-state-pending 1) -(def ^:const community-request-to-join-state-declined 2) (def ^:const community-request-to-join-state-accepted 3) -(def ^:const community-request-to-join-state-cancelled 4) - (def ^:const community-id-length 68) -(def ^:const toast-chain-down-duration 5000) ; BIP44 Wallet Root Key, the extended key from which any wallet can be derived (def ^:const path-wallet-root "m/44'/60'/0'/0") @@ -225,19 +175,9 @@ (def ^:const path-ledger-live "m/44'/60'") (def ^:const path-keepkey "m/44'/60'") -(def ^:const path-default-wallet-keyword (keyword path-default-wallet)) -(def ^:const path-whisper-keyword (keyword path-whisper)) -(def ^:const path-wallet-root-keyword (keyword path-wallet-root)) -(def ^:const path-eip1581-keyword (keyword path-eip1581)) - -(def ^:const method-id-transfer "0xa9059cbb") -(def ^:const method-id-approve "0x095ea7b3") -(def ^:const method-id-approve-and-call "0xcae9ca51") (def regx-string-universal-link-encoded-data-base64 "(?:[A-Za-z0-9+/_-]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?") -(def regx-universal-link-encoded-data-base64 - (str "^" regx-string-universal-link-encoded-data-base64 "$")) (def regx-string-any-ascii "[\\x00-\\x7F]") (def regx-string-compressed-key "zQ3[0-9A-HJ-NP-Za-km-z]{46}") (def regx-string-public-key "0x04[0-9a-f]{128}") @@ -247,9 +187,6 @@ (def regx-private-key #"^[0-9a-fA-F]{64}$") (def regx-emoji #"^((?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC69\uDC6E\uDC70-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD26\uDD30-\uDD39\uDD3D\uDD3E\uDDD1-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])?|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDEEB\uDEEC\uDEF4-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])\uFE0F|[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF])+$") -(def regx-bold #"\*[^*]+\*") -(def regx-italic #"~[^~]+~") -(def regx-backquote #"`[^`]+`") (def regx-string-universal-link (str "((^https?://status.app/)|(^status-app://))" "(" @@ -266,12 +203,9 @@ (str "wallet/" regx-string-any-ascii "+")]) ")$")) (def regx-universal-link (re-pattern regx-string-universal-link)) -(def regx-community-universal-link #"((^https?://status.app/)|(^status-app://))c/([\x00-\x7F]+)$") (def regx-deep-link #"((^ethereum:.*)|(^status-app://[\x00-\x7F]+$))") (def regx-ens #"^(?=.{5,255}$)([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$") - (def regx-starts-with-uuid #"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") -(def regx-full-or-partial-address #"^0x[a-fA-F0-9]{1,40}$") ;; Wallet Connect (def ^:const wallet-connect-metadata-icon @@ -323,8 +257,6 @@ (def ^:const history-state-changed "history-state-changed") (def ^:const web3-send-async-read-only "web3-send-async-read-only") (def ^:const web3-send-async-callback "web3-send-async-callback") -(def ^:const scan-qr-code "scan-qr-code") - (def ^:const two-mins (* 2 60)) (def ^:const one-day (* 60 60 24)) (def ^:const three-days (* one-day 3)) @@ -332,8 +264,6 @@ (def ^:const one-week (* one-day 7)) (def ^:const one-month (* one-day 31)) -(def ^:const privacy-policy-link "https://status.im/privacy-policy/") -(def ^:const terms-of-service-link "https://status.im/terms-of-use") (def ^:const create-account-link "https://status.app/help/wallet/create-wallet-accounts") (def ^:const mobile-upvote-link "https://status-mobile.featureupvote.com") @@ -347,8 +277,6 @@ (def ^:const sticker-pack-status-pending 2) (def ^:const sticker-pack-status-owned 3) -(def ^:const community-member-role-all 1) -(def ^:const community-member-role-manage-users 2) (def ^:const community-member-role-moderator 3) (def ^:const delete-message-undo-time-limit-ms 4000) @@ -379,15 +307,6 @@ 4 (- (* image-size 0.5) 0.5) 5 (- (* image-size 0.5) 0.5)}}) -(def ^:const spam-message-frequency-threshold 4) -(def ^:const spam-interval-ms 1000) -(def ^:const default-cooldown-period-ms 10000) -(def ^:const cooldown-reset-threshold 3) -(def ^:const cooldown-periods-ms - {1 2000 - 2 5000 - 3 10000}) - ;; any message that comes after this amount of ms will be grouped separately (def ^:const group-ms 300000) @@ -401,19 +320,15 @@ (def ^:const local-pairing-role-receiver "receiver") ;; sender and receiver events -(def ^:const local-pairing-event-peer-discovered "peer-discovered") (def ^:const local-pairing-event-connection-success "connection-success") (def ^:const local-pairing-event-connection-error "connection-error") (def ^:const local-pairing-event-transfer-success "transfer-success") (def ^:const local-pairing-event-transfer-error "transfer-error") -(def ^:const local-pairing-event-received-installation "received-installation") + ;; receiver events (def ^:const local-pairing-event-received-account "received-account") -(def ^:const local-pairing-event-process-success "process-success") (def ^:const local-pairing-event-process-error "process-error") -(def ^:const local-pairing-event-received-keystore-files "received-keystore-files") - (def ^:const local-pairing-event-errors #{local-pairing-event-connection-error local-pairing-event-transfer-error @@ -421,9 +336,7 @@ (def ^:const local-pairing-action-connect 1) (def ^:const local-pairing-action-pairing-account 2) -(def ^:const local-pairing-action-sync-device 3) (def ^:const local-pairing-action-pairing-installation 4) -(def ^:const local-pairing-action-peer-discovery 5) (def ^:const local-pairing-action-keystore-files-transfer 6) (def ^:const serialization-key @@ -440,20 +353,10 @@ keys with base16 hexadecimal encoding" "f") -(def ^:const multi-code-prefix - "We prefix our keys with 0xe701 prior to serialisation them" - "0xe701") - (def ^:const appearance-type-system 0) (def ^:const appearance-type-light 1) (def ^:const appearance-type-dark 2) -(def ^:const bottom-sheet-animation-delay 450) -(def ^:const local-pair-event-process-success "process-success") -(def ^:const local-pair-event-process-error "process-error") -(def ^:const local-pair-action-connect 1) -(def ^:const local-pair-action-pairing-account 2) -(def ^:const local-pair-action-sync-device 3) (def ^:const everyone-mention-id "0x00001") @@ -463,7 +366,6 @@ (def ^:const auth-method-password "password") (def ^:const auth-method-biometric "biometric") -(def ^:const auth-method-biometric-prepare "biometric-prepare") (def ^:const auth-method-none "none") ;; NOTE all android biometrics falls under :Biometrics @@ -471,10 +373,6 @@ (def ^:const biometrics-type-touch-id :TouchID) (def ^:const biometrics-type-face-id :FaceID) -(def ^:const onboarding-generating-keys-navigation-retry-ms 3000) - -(def ^:const image-description-in-lightbox? false) - (def ^:const audio-max-duration-ms 120000) (def ^:const onboarding-modal-animation-duration 300) @@ -503,9 +401,6 @@ {:ethereum "ethereum" :sepolia "sepolia"}) -(def ^:const ethereum "ethereum") -(def ^:const sepolia "sepolia") - (def ^:const mainnet-chain-ids #{ethereum-mainnet-chain-id arbitrum-mainnet-chain-id optimism-mainnet-chain-id}) @@ -517,8 +412,6 @@ (def ^:const optimism-short-name "oeth") (def ^:const arbitrum-short-name "arb1") -(def ^:const default-multichain-address-prefix "eth:oeth:arb1:") - (def ^:const mainnet-abbreviated-name "Eth.") (def ^:const optimism-abbreviated-name "Oeth.") (def ^:const arbitrum-abbreviated-name "Arb1.") @@ -547,43 +440,18 @@ (def ^:const wallet-account-name-max-length 20) -(def ^:const status-address-domain ".stateofus.eth") -(def ^:const eth-address-domain ".eth") -(def ^:const gas-rate-low 0) (def ^:const gas-rate-medium 1) -(def ^:const gas-rate-high 2) - (def ^:const send-type-transfer 0) -(def ^:const send-type-ens-register 1) -(def ^:const send-type-ens-release 2) -(def ^:const send-type-ens-set-pub-key 3) -(def ^:const send-type-stickers-buy 4) (def ^:const send-type-bridge 5) (def ^:const send-type-erc-721-transfer 6) (def ^:const send-type-erc-1155-transfer 7) (def ^:const send-type-swap 8) -(def ^:const multi-transaction-type-send 0) -(def ^:const multi-transaction-type-approve 1) -(def ^:const multi-transaction-type-bridge 2) -(def ^:const multi-transaction-type-swap 3) -(def ^:const multi-transaction-type-unknown 255) - -(def ^:const contract-function-signature-erc20-approve "approve(address,uint256)") - -(def ^:const bridge-name-transfer "Transfer") -(def ^:const bridge-name-erc-721-transfer "ERC721Transfer") -(def ^:const bridge-name-erc-1155-transfer "ERC1155Transfer") (def ^:const bridge-name-hop "Hop") -(def ^:const bridge-name-paraswap "Paraswap") -(def ^:const bridge-name-celer "CBridge") (def ^:const bridge-assets #{"ETH" "USDT" "USDC" "DAI"}) -(def ^:const wallet-contract-type-uknown 0) -(def ^:const wallet-contract-type-erc-20 1) -(def ^:const wallet-contract-type-erc-721 2) (def ^:const wallet-contract-type-erc-1155 3) (def ^:const alert-banner-height 40) diff --git a/src/status_im/contexts/centralized_metrics/events.cljs b/src/status_im/contexts/centralized_metrics/events.cljs index f758922a0d7f..037cdeb9e8ad 100644 --- a/src/status_im/contexts/centralized_metrics/events.cljs +++ b/src/status_im/contexts/centralized_metrics/events.cljs @@ -21,6 +21,8 @@ (native-module/add-centralized-metric event)))) context) +;; ignore warning, interceptor used from interceptor_metrics.cljc +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (def interceptor (interceptor/->interceptor :id :centralized-metrics diff --git a/src/status_im/contexts/chat/events.cljs b/src/status_im/contexts/chat/events.cljs index f6a9943f019a..8ba733b1aa2c 100644 --- a/src/status_im/contexts/chat/events.cljs +++ b/src/status_im/contexts/chat/events.cljs @@ -44,11 +44,6 @@ ([cofx chat-id] (community-chat? (get-chat cofx chat-id)))) -(defn active-chat? - [cofx chat-id] - (let [chat (get-chat cofx chat-id)] - (:active chat))) - (defn group-chat? ([chat] (and (multi-user-chat? chat) @@ -162,7 +157,7 @@ (rf/defn deactivate-chat "Deactivate chat in db, no side effects" - [{:keys [db now] :as cofx} chat-id] + [{:keys [db] :as cofx} chat-id] (rf/merge cofx {:db (-> (if (get-in db [:chats chat-id :muted]) @@ -268,7 +263,7 @@ (rf/defn close-and-remove-chat "Closes the chat and removes it from chat list while retaining history, producing all necessary effects for that" {:events [:chat.ui/close-and-remove-chat]} - [{:keys [db now] :as cofx} chat-id] + [cofx chat-id] (rf/merge cofx {:effects/push-notifications-clear-message-notifications [chat-id]} (deactivate-chat chat-id) diff --git a/src/status_im/contexts/chat/events_test.cljs b/src/status_im/contexts/chat/events_test.cljs index efa3211affa7..e0ad6ebce34a 100644 --- a/src/status_im/contexts/chat/events_test.cljs +++ b/src/status_im/contexts/chat/events_test.cljs @@ -73,15 +73,6 @@ (let [cofx {:db {:chats {chat-id {}}}}] (is (not (chat/group-chat? cofx chat-id))))))) -(def test-db - {:profile/profile {:public-key "me"} - - :messages {"status" {"4" {} "5" {} "6" {}}} - :chats {"status" {:public? true - :group-chat true} - "opened" {} - "1-1" {}}}) - (deftest navigate-to-chat-test (let [chat-id "test_chat" db {:pagination-info {chat-id {:all-loaded? true}}}] diff --git a/src/status_im/contexts/chat/group/common/style.cljs b/src/status_im/contexts/chat/group/common/style.cljs index 5f5a5a75bcb0..3e4d4af94e92 100644 --- a/src/status_im/contexts/chat/group/common/style.cljs +++ b/src/status_im/contexts/chat/group/common/style.cljs @@ -3,13 +3,6 @@ (def avatar {:width 88 :margin-top 12 :margin-left 20}) -(def hole - {:y (- 80 32) - :x (+ (- 80 32) 8) - :width 32 - :height 32 - :borderRadius 10}) - (def camera {:position :absolute :right 0 :bottom 0}) (defn color-label diff --git a/src/status_im/contexts/chat/group/details/style.cljs b/src/status_im/contexts/chat/group/details/style.cljs index 624b1f8e2f1a..225fd3049e07 100644 --- a/src/status_im/contexts/chat/group/details/style.cljs +++ b/src/status_im/contexts/chat/group/details/style.cljs @@ -7,20 +7,6 @@ :margin-bottom 20 :padding-horizontal 20}) -(defn action-container - [color theme] - {:background-color (colors/theme-alpha color 0.1 0.1 theme) - :flex 0.29 - :border-radius 16 - :padding 12}) - -(defn count-container - [theme] - {:width 16 - :height 16 - :border-radius 6 - :background-color (colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)}) - (defn close-icon [theme] {:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme) diff --git a/src/status_im/contexts/chat/home/add_new_contact/style.cljs b/src/status_im/contexts/chat/home/add_new_contact/style.cljs index f7364eb0f7a1..91406c8e9d2c 100644 --- a/src/status_im/contexts/chat/home/add_new_contact/style.cljs +++ b/src/status_im/contexts/chat/home/add_new_contact/style.cljs @@ -80,6 +80,4 @@ colors/neutral-40 theme)}) -(def button-view-profile - {:margin-top 24 - :width "100%"}) + diff --git a/src/status_im/contexts/chat/home/style.cljs b/src/status_im/contexts/chat/home/style.cljs deleted file mode 100644 index 58735c9ea159..000000000000 --- a/src/status_im/contexts/chat/home/style.cljs +++ /dev/null @@ -1,26 +0,0 @@ -(ns status-im.contexts.chat.home.style - (:require - [react-native.platform :as platform] - [react-native.safe-area :as safe-area])) - -(def tabs - {:padding-horizontal 20 - :padding-top 16 - :padding-bottom 12}) - -(def blur - {:position :absolute - :top 0 - :right 0 - :left 0 - :bottom 0}) - -(defn blur-container - [] - {:overflow (if platform/ios? :visible :hidden) - :position :absolute - :z-index 1 - :top 0 - :right 0 - :left 0 - :padding-top (safe-area/get-top)}) diff --git a/src/status_im/contexts/chat/messenger/composer/constants.cljs b/src/status_im/contexts/chat/messenger/composer/constants.cljs index b400331f6851..418264d5d545 100644 --- a/src/status_im/contexts/chat/messenger/composer/constants.cljs +++ b/src/status_im/contexts/chat/messenger/composer/constants.cljs @@ -1,18 +1,7 @@ -(ns status-im.contexts.chat.messenger.composer.constants - (:require - [quo.foundations.typography :as typography] - [react-native.platform :as platform])) - -(def ^:const bar-container-height 20) - -(def ^:const input-height 32) +(ns status-im.contexts.chat.messenger.composer.constants) (def ^:const actions-container-height 56) -(def ^:const composer-default-height (+ bar-container-height input-height actions-container-height)) - -(def ^:const line-height (if platform/ios? 18 (:line-height typography/paragraph-1))) - (def ^:const images-padding-top 12) (def ^:const images-padding-bottom 8) (def ^:const images-container-height diff --git a/src/status_im/contexts/chat/messenger/composer/events.cljs b/src/status_im/contexts/chat/messenger/composer/events.cljs index e10e89fd5cbc..61a2cb0c3e5e 100644 --- a/src/status_im/contexts/chat/messenger/composer/events.cljs +++ b/src/status_im/contexts/chat/messenger/composer/events.cljs @@ -8,7 +8,6 @@ [taoensso.timbre :as log] [utils.debounce :as debounce] [utils.emojilib :as emoji] - [utils.i18n :as i18n] [utils.re-frame :as rf] utils.string)) @@ -28,35 +27,12 @@ (let [current-chat-id (:current-chat-id db)] {:db (assoc-in db [:chat/inputs current-chat-id :input-ref] input-ref)})) -(rf/defn set-input-content-height - {:events [:chat.ui/set-input-content-height]} - [{db :db} content-height chat-id] - (let [current-chat-id (or chat-id (:current-chat-id db))] - {:db (assoc-in db [:chat/inputs current-chat-id :input-content-height] content-height)})) - -(rf/defn set-input-maximized - {:events [:chat.ui/set-input-maximized]} - [{db :db} maximized? chat-id] - (let [current-chat-id (or chat-id (:current-chat-id db))] - {:db (assoc-in db [:chat/inputs current-chat-id :input-maximized?] maximized?)})) - (rf/defn set-input-focused - {:events [:chat.ui/set-input-focused]} + {:events [:chat.ui/setnn-input-focused]} [{db :db} focused? chat-id] (let [current-chat-id (or chat-id (:current-chat-id db))] {:db (assoc-in db [:chat/inputs current-chat-id :focused?] focused?)})) -(rf/defn set-input-audio - {:events [:chat.ui/set-input-audio]} - [{db :db} audio chat-id] - (let [current-chat-id (or chat-id (:current-chat-id db))] - {:db (assoc-in db [:chat/inputs current-chat-id :audio] audio)})) - -(rf/defn set-recording - {:events [:chat.ui/set-recording]} - [{db :db} recording?] - {:db (assoc db :chats/recording? recording?)}) - (rf/defn reply-to-message "Sets reference to previous chat message and focuses on input" {:events [:chat.ui/reply-to-message]} @@ -200,25 +176,6 @@ (link-preview/reset-unfurled) (messages.transport/send-chat-messages messages))))) -(rf/defn send-audio-message - {:events [:chat/send-audio]} - [{:keys [db] :as cofx} audio-path duration] - (let [{:keys [current-chat-id]} db - {:keys [message-id]} - (get-in db [:chat/inputs current-chat-id :metadata :responding-to-message])] - (when-not (string/blank? audio-path) - (rf/merge - {:db (assoc-in db [:chat/inputs current-chat-id :metadata :responding-to-message] nil)} - (messages.transport/send-chat-messages - [(merge - {:chat-id current-chat-id - :content-type constants/content-type-audio - :audio-path audio-path - :audio-duration-ms duration - :text (i18n/label :t/update-to-listen-audio {"locale" "en"})} - (when message-id - {:response-to message-id}))]))))) - (defn- process-link-previews [link-previews] (->> link-previews @@ -231,7 +188,7 @@ (rf/defn send-edited-message [{:keys [db] - :as cofx} text {:keys [message-id quoted-message chat-id]}] + :as cofx} text {:keys [message-id quoted-message]}] (rf/merge cofx {:json-rpc/call diff --git a/src/status_im/contexts/chat/messenger/composer/gradients/style.cljs b/src/status_im/contexts/chat/messenger/composer/gradients/style.cljs deleted file mode 100644 index c500eccb7532..000000000000 --- a/src/status_im/contexts/chat/messenger/composer/gradients/style.cljs +++ /dev/null @@ -1,42 +0,0 @@ -(ns status-im.contexts.chat.messenger.composer.gradients.style - (:require - [quo.foundations.colors :as colors] - [react-native.reanimated :as reanimated] - [status-im.contexts.chat.messenger.composer.constants :as constants])) - -(defn- top-gradient-style - [opacity z-index showing-extra-space?] - (reanimated/apply-animations-to-style - {:opacity opacity} - {:height (when (pos-int? z-index) 80) - :position :absolute - :z-index z-index - :top (+ constants/bar-container-height - (if showing-extra-space? - constants/edit-container-height - 0)) - :left 0 - :right 0})) - -(defn top-gradient - [opacity z-index showing-extra-space? theme] - {:colors [(colors/theme-colors colors/white-opa-0 colors/neutral-95-opa-0 theme) - (colors/theme-colors colors/white colors/neutral-95 theme)] - :start {:x 0 :y 1} - :end {:x 0 :y 0} - :style (top-gradient-style opacity z-index showing-extra-space?)}) - -(def bottom-gradient-style - {:height constants/line-height - :position :absolute - :bottom 0 - :left 0 - :right 0}) - -(defn bottom-gradient - [theme] - {:colors [(colors/theme-colors colors/white colors/neutral-95 theme) - (colors/theme-colors colors/white-opa-0 colors/neutral-95-opa-0 theme)] - :start {:x 0 :y 1} - :end {:x 0 :y 0} - :style bottom-gradient-style}) diff --git a/src/status_im/contexts/chat/messenger/composer/gradients/view.cljs b/src/status_im/contexts/chat/messenger/composer/gradients/view.cljs deleted file mode 100644 index 998954e01c33..000000000000 --- a/src/status_im/contexts/chat/messenger/composer/gradients/view.cljs +++ /dev/null @@ -1,30 +0,0 @@ -(ns status-im.contexts.chat.messenger.composer.gradients.view - (:require - [quo.theme] - [react-native.core :as rn] - [react-native.linear-gradient :as linear-gradient] - [react-native.reanimated :as reanimated] - [status-im.contexts.chat.messenger.composer.gradients.style :as style] - [utils.re-frame :as rf])) - -(defn f-view - [{:keys [input-ref]} - {:keys [gradient-z-index]} - {:keys [gradient-opacity]} - show-bottom-gradient?] - (let [theme (quo.theme/use-theme) - showing-extra-space? (boolean (or (rf/sub [:chats/edit-message]) - (rf/sub [:chats/reply-message])))] - [:<> - [reanimated/linear-gradient - (style/top-gradient gradient-opacity @gradient-z-index showing-extra-space? theme)] - (when show-bottom-gradient? - [rn/pressable - {:on-press #(when @input-ref (.focus ^js @input-ref)) - :style {:z-index 1} - :accessibility-label :bottom-gradient} - [linear-gradient/linear-gradient (style/bottom-gradient theme)]])])) - -(defn view - [props state animations show-bottom-gradient?] - [:f> f-view props state animations show-bottom-gradient?]) diff --git a/src/status_im/contexts/chat/messenger/composer/handlers.cljs b/src/status_im/contexts/chat/messenger/composer/handlers.cljs index 22a8dad1caef..38094342c819 100644 --- a/src/status_im/contexts/chat/messenger/composer/handlers.cljs +++ b/src/status_im/contexts/chat/messenger/composer/handlers.cljs @@ -1,10 +1,7 @@ (ns status-im.contexts.chat.messenger.composer.handlers (:require [clojure.string :as string] - [oops.core :as oops] - [react-native.core :as rn] [status-im.contexts.chat.messenger.composer.constants :as constants] - [status-im.contexts.chat.messenger.composer.selection :as selection] [utils.debounce :as debounce] [utils.number] [utils.re-frame :as rf])) @@ -17,24 +14,3 @@ (if (string/ends-with? text "@") (rf/dispatch [:mention/on-change-text text]) (debounce/debounce-and-dispatch [:mention/on-change-text text] 300))) - -(defn selection-change - "A method that handles our custom selector for `B I U`" - [event - {:keys [input-ref selection-event selection-manager]} - {:keys [lock-selection? cursor-position first-level? menu-items]}] - (let [start (oops/oget event "nativeEvent.selection.start") - end (oops/oget event "nativeEvent.selection.end") - selection? (not= start end) - text-input-handle (rn/find-node-handle @input-ref)] - (when-not @lock-selection? - (reset! cursor-position end)) - (when (and selection? (not @first-level?)) - (js/setTimeout #(oops/ocall selection-manager :startActionMode text-input-handle) 500)) - (when (and (not selection?) (not @first-level?)) - (oops/ocall selection-manager :hideLastActionMode) - (selection/reset-to-first-level-menu first-level? menu-items)) - (when @selection-event - (let [{:keys [start end text-input-handle]} @selection-event] - (selection/update-selection text-input-handle start end) - (reset! selection-event nil))))) diff --git a/src/status_im/contexts/chat/messenger/composer/link_preview/events.cljs b/src/status_im/contexts/chat/messenger/composer/link_preview/events.cljs index 8b823736f1b7..985e0c1493fe 100644 --- a/src/status_im/contexts/chat/messenger/composer/link_preview/events.cljs +++ b/src/status_im/contexts/chat/messenger/composer/link_preview/events.cljs @@ -129,7 +129,7 @@ (rf/defn unfurl-parsed-urls-error {:events [:link-preview/unfurl-parsed-urls-error]} - [{:keys [db]} request-id error] + [_cofx request-id error] (log/error "Failed to unfurl URLs" {:request-id request-id :error error diff --git a/src/status_im/contexts/chat/messenger/composer/mentions/style.cljs b/src/status_im/contexts/chat/messenger/composer/mentions/style.cljs index 1639d2b1b822..158aa2e254ff 100644 --- a/src/status_im/contexts/chat/messenger/composer/mentions/style.cljs +++ b/src/status_im/contexts/chat/messenger/composer/mentions/style.cljs @@ -14,18 +14,6 @@ :shadow-offset {:width 0 :height (colors/theme-colors 8 12 theme)}) (assoc styles :elevation 10))) -(defn inner - [top theme] - (add-shadow theme - {:position :absolute - :top (- (+ 8 top)) - :left 8 - :right 8 - :border-radius 16 - :z-index 4 - :max-height constants/mentions-max-height - :background-color (colors/theme-colors colors/white colors/neutral-95 theme)})) - (defn container [opacity top theme] [{:opacity opacity} diff --git a/src/status_im/contexts/chat/messenger/composer/selection.cljs b/src/status_im/contexts/chat/messenger/composer/selection.cljs index bcf872420bb7..e2451afe38e2 100644 --- a/src/status_im/contexts/chat/messenger/composer/selection.cljs +++ b/src/status_im/contexts/chat/messenger/composer/selection.cljs @@ -83,28 +83,3 @@ :strikethrough #(append-markdown-char % "~~")}) (def second-level-menu-items (map i18n/label (keys second-level-menus))) - -(defn on-menu-item-touched - [{:keys [first-level? event-type] :as params}] - (let [menus (if @first-level? first-level-menus second-level-menus) - menu-item-key (nth (keys menus) event-type) - action (get menus menu-item-key)] - (action params))) - -(defn on-selection - [event - {:keys [input-ref selection-event]} - {:keys [first-level? menu-items]}] - (let [{:strs [eventType content selectionStart - selectionEnd]} (js->clj (oops/oget event "nativeEvent")) - full-text (:input-text (rf/sub [:chats/current-chat-input]))] - (on-menu-item-touched {:first-level? first-level? - :event-type eventType - :content content - :selection-start selectionStart - :selection-end selectionEnd - :text-input @input-ref - :text-input-handle (rn/find-node-handle @input-ref) - :full-text full-text - :menu-items menu-items - :selection-event selection-event}))) diff --git a/src/status_im/contexts/chat/messenger/composer/style.cljs b/src/status_im/contexts/chat/messenger/composer/style.cljs index 007e264718f7..720b373e9ddd 100644 --- a/src/status_im/contexts/chat/messenger/composer/style.cljs +++ b/src/status_im/contexts/chat/messenger/composer/style.cljs @@ -1,27 +1,7 @@ (ns status-im.contexts.chat.messenger.composer.style (:require [quo.foundations.colors :as colors] - [quo.foundations.typography :as typography] - [react-native.reanimated :as reanimated] - [status-im.contexts.chat.messenger.composer.constants :as constants])) - -(def border-top-radius 20) - -(def bar-container - {:height constants/bar-container-height - :left 0 - :right 0 - :top 0 - :z-index 1 - :justify-content :center - :align-items :center}) - -(defn bar - [theme] - {:width 32 - :height 4 - :border-radius 100 - :background-color (colors/theme-colors colors/neutral-100-opa-5 colors/white-opa-10 theme)}) + [quo.foundations.typography :as typography])) (defn input-text [theme] @@ -31,15 +11,3 @@ :top 0 :left 0 :max-height 150)) - -(defn shell-button - [translate-y opacity] - (reanimated/apply-animations-to-style - {:transform [{:translate-y translate-y}] - :opacity opacity} - {})) - -(def scroll-to-bottom-button - {:position :absolute - :right 0 - :left 0}) diff --git a/src/status_im/contexts/chat/messenger/composer/utils.cljs b/src/status_im/contexts/chat/messenger/composer/utils.cljs index 2a019afb13e1..a82199d6230e 100644 --- a/src/status_im/contexts/chat/messenger/composer/utils.cljs +++ b/src/status_im/contexts/chat/messenger/composer/utils.cljs @@ -1,21 +1,8 @@ (ns status-im.contexts.chat.messenger.composer.utils (:require - [status-im.contexts.chat.messenger.composer.constants :as constants] [utils.number] [utils.re-frame :as rf])) -(defn calc-top-content-height - [reply? edit?] - (cond-> 0 - reply? (+ constants/reply-container-height) - edit? (+ constants/edit-container-height))) - -(defn calc-bottom-content-height - [images link-previews?] - (cond-> 0 - (seq images) (+ constants/images-container-height) - link-previews? (+ constants/links-container-height))) - (defn blur-input [input-ref] (when @input-ref @@ -38,26 +25,3 @@ 100) (.setNativeProps ^js @input-ref (clj->js {:text ""})) (rf/dispatch [:chat.ui/cancel-message-edit])) - -(defn calc-suggestions-position - [cursor-pos max-height size - {:keys [maximized?]} - {:keys [insets curr-height window-height keyboard-height reply edit]} - images - link-previews?] - (let [base (+ constants/composer-default-height (:bottom insets) 8) - base (+ base (- curr-height constants/input-height)) - base (+ base (calc-top-content-height reply edit)) - view-height (- window-height keyboard-height (:top insets)) - container-height (utils.number/value-in-range - (* (/ constants/mentions-max-height 4) size) - (/ constants/mentions-max-height 4) - constants/mentions-max-height)] - (if @maximized? - (if (< (+ cursor-pos container-height) max-height) - (+ constants/actions-container-height (:bottom insets)) - (+ constants/actions-container-height (:bottom insets) (- max-height cursor-pos) 18)) - (if (< (+ base container-height) view-height) - (let [bottom-content-height (calc-bottom-content-height images link-previews?)] - (+ base bottom-content-height)) - (+ constants/actions-container-height (:bottom insets) (- curr-height cursor-pos) 18))))) diff --git a/src/status_im/contexts/chat/messenger/messages/constants.cljs b/src/status_im/contexts/chat/messenger/messages/constants.cljs index ffcc6d4604df..edd58c4c2a83 100644 --- a/src/status_im/contexts/chat/messenger/messages/constants.cljs +++ b/src/status_im/contexts/chat/messenger/messages/constants.cljs @@ -3,4 +3,3 @@ ;;;; Navigation (def ^:const top-bar-height 56) (def ^:const pinned-banner-height 40) -(def ^:const header-container-radius 20) diff --git a/src/status_im/contexts/chat/messenger/messages/content/audio/style.cljs b/src/status_im/contexts/chat/messenger/messages/content/audio/style.cljs index 4abf63943d7d..e5001d8bbcc0 100644 --- a/src/status_im/contexts/chat/messenger/messages/content/audio/style.cljs +++ b/src/status_im/contexts/chat/messenger/messages/content/audio/style.cljs @@ -16,10 +16,6 @@ :border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme) :background-color (colors/theme-colors colors/neutral-5 colors/neutral-80-opa-40 theme)}) -(def play-pause-slider-container - {:flex-direction :row - :align-items :center}) - (def slider-container {:position :absolute :left 60 diff --git a/src/status_im/contexts/chat/messenger/messages/content/pin/style.cljs b/src/status_im/contexts/chat/messenger/messages/content/pin/style.cljs index f1c52b2ea6bf..5fce92ffe3f7 100644 --- a/src/status_im/contexts/chat/messenger/messages/content/pin/style.cljs +++ b/src/status_im/contexts/chat/messenger/messages/content/pin/style.cljs @@ -2,9 +2,6 @@ (:require [quo.foundations.colors :as colors])) -(def system-message-default-size 34) -(def system-message-margin-right 8) - (def pin-indicator-container {:padding-left 42 :margin-bottom 2 @@ -14,28 +11,3 @@ (def pin-author-text {:color colors/primary-50 :margin-left 2}) - -(defn pinned-message-text - [theme] - {:color (colors/theme-colors colors/neutral-100 colors/white theme) - :margin-left 4}) - -(def system-message-container - {:flex-direction :row :margin-vertical 8}) - -(def system-message-inner-container - {:width system-message-default-size - :height system-message-default-size - :border-radius system-message-default-size - :margin-right system-message-margin-right - :justify-content :center - :align-items :center - :background-color colors/primary-50-opa-10}) - -(def system-message-author-container - {:flex-direction :row - :align-items :baseline}) - -(def system-message-timestamp-container - {:padding-left 8 - :color colors/neutral-50}) diff --git a/src/status_im/contexts/chat/messenger/messages/delete_message/events.cljs b/src/status_im/contexts/chat/messenger/messages/delete_message/events.cljs index 23a9e2a8373f..50e5b903842e 100644 --- a/src/status_im/contexts/chat/messenger/messages/delete_message/events.cljs +++ b/src/status_im/contexts/chat/messenger/messages/delete_message/events.cljs @@ -158,7 +158,7 @@ (rf/defn delete-and-send {:events [:chat.ui/delete-message-and-send]} [{:keys [db]} {:keys [message-id chat-id]} force?] - (when-let [message (get-in db [:messages chat-id message-id])] + (when (get-in db [:messages chat-id message-id]) (when (or force? (check-before-delete-and-send db chat-id message-id)) (let [unpin-locally? ;; this only check against local client data generally msg is already unpinned at delete diff --git a/src/status_im/contexts/chat/messenger/messages/delete_message_for_me/events.cljs b/src/status_im/contexts/chat/messenger/messages/delete_message_for_me/events.cljs index 05b8f1195a1e..6faba23a13f0 100644 --- a/src/status_im/contexts/chat/messenger/messages/delete_message_for_me/events.cljs +++ b/src/status_im/contexts/chat/messenger/messages/delete_message_for_me/events.cljs @@ -104,7 +104,7 @@ (rf/defn delete-and-sync {:events [:chat.ui/delete-message-for-me-and-sync]} [{:keys [db]} {:keys [message-id chat-id]} force?] - (when-let [message (get-in db [:messages chat-id message-id])] + (when-let [_message (get-in db [:messages chat-id message-id])] (when (or force? (check-before-delete-and-sync db chat-id message-id)) {:db (update-db-clear-undo-timer db chat-id message-id) :json-rpc/call [{:method "wakuext_deleteMessageForMeAndSync" diff --git a/src/status_im/contexts/chat/messenger/messages/drawers/view.cljs b/src/status_im/contexts/chat/messenger/messages/drawers/view.cljs index 99e595da8ca9..5f6a37213f5d 100644 --- a/src/status_im/contexts/chat/messenger/messages/drawers/view.cljs +++ b/src/status_im/contexts/chat/messenger/messages/drawers/view.cljs @@ -186,13 +186,6 @@ :icon :i/delete :id :delete-for-all})))) -(defn extract-id - [reactions id] - (->> reactions - (filter (fn [{:keys [emoji-id]}] (= emoji-id id))) - first - :emoji-reaction-id)) - (defn reactions [{:keys [chat-id message-id]}] (let [msg-reactions (rf/sub [:chats/message-reactions message-id chat-id]) diff --git a/src/status_im/contexts/chat/messenger/messages/list/events_test.cljs b/src/status_im/contexts/chat/messenger/messages/list/events_test.cljs index 976ece2ec1c9..5c386769cb89 100644 --- a/src/status_im/contexts/chat/messenger/messages/list/events_test.cljs +++ b/src/status_im/contexts/chat/messenger/messages/list/events_test.cljs @@ -51,23 +51,6 @@ (is (:last-in-group? actual-m2)) (is (:last-in-group? actual-m3)))))) -(def ascending-range - (mapv - #(let [i (+ 100000 %)] - {:clock-value i - :whisper-timestamp i - :timestamp i - :message-id (str i)}) - (range 2000))) - -(def descending-range (reverse ascending-range)) - -(def random-range (shuffle ascending-range)) - -(defnp build-message-list - [messages] - (s/add-many nil messages)) - (defnp append-to-message-list [l message] (s/add l message)) diff --git a/src/status_im/contexts/chat/messenger/messages/list/view.cljs b/src/status_im/contexts/chat/messenger/messages/list/view.cljs index 5b6002405c67..e0c969fd6df4 100644 --- a/src/status_im/contexts/chat/messenger/messages/list/view.cljs +++ b/src/status_im/contexts/chat/messenger/messages/list/view.cljs @@ -10,13 +10,10 @@ [react-native.hooks :as hooks] [react-native.platform :as platform] [react-native.reanimated :as reanimated] - [status-im.common.home.actions.view :as home.actions] [status-im.constants :as constants] - [status-im.contexts.chat.messenger.composer.constants :as composer.constants] [status-im.contexts.chat.messenger.messages.content.view :as message] [status-im.contexts.chat.messenger.messages.list.state :as state] [status-im.contexts.chat.messenger.messages.list.style :as style] - [utils.i18n :as i18n] [utils.re-frame :as rf] [utils.worklets.chat.messenger.messages :as worklets])) @@ -66,62 +63,6 @@ :parent-height parent-height :animated? false}])) -(defn header-height - [{:keys [insets able-to-send-message? images reply edit link-previews? input-content-height]}] - (if able-to-send-message? - (cond-> composer.constants/composer-default-height - (seq images) - (+ composer.constants/images-container-height) - - reply - (+ composer.constants/reply-container-height) - - edit - (+ composer.constants/edit-container-height) - - link-previews? - (+ composer.constants/links-container-height) - - (and input-content-height (not= input-content-height composer.constants/input-height)) - (+ composer.constants/input-height) - - true - (+ (:bottom insets))) - (- 70 (:bottom insets)))) - -(defn actions - [chat-id cover-bg-color] - (let [latest-pin-text (rf/sub [:chats/last-pinned-message-text chat-id]) - pins-count (rf/sub [:chats/pin-messages-count chat-id]) - {:keys [muted muted-till chat-type]} (rf/sub [:chats/chat-by-id chat-id]) - community-channel? (= constants/community-chat-type chat-type) - muted? (and muted (some? muted-till)) - mute-chat-label (if community-channel? :t/mute-channel :t/mute-chat) - unmute-chat-label (if community-channel? :t/unmute-channel :t/unmute-chat)] - [quo/channel-actions - {:actions - [{:accessibility-label :action-button-pinned - :big? true - :label (if (pos? pins-count) latest-pin-text (i18n/label :t/no-pinned-messages)) - :customization-color cover-bg-color - :icon :i/pin - :counter-value pins-count - :on-press (fn [] - (rf/dispatch [:pin-message/show-pins-bottom-sheet - chat-id]))} - {:accessibility-label :action-button-mute - :label (i18n/label (if muted - unmute-chat-label - mute-chat-label)) - :customization-color cover-bg-color - :icon (if muted? :i/activity-center :i/muted) - :on-press (fn [] - (if muted? - (home.actions/unmute-chat-action chat-id) - (home.actions/mute-chat-action chat-id - chat-type - muted?)))}]}])) - (defn more-messages-loader [{:keys [chat-id] :as props}] (let [loading-messages? (rf/sub [:chats/loading-messages? chat-id]) diff --git a/src/status_im/contexts/chat/messenger/messages/pin/events.cljs b/src/status_im/contexts/chat/messenger/messages/pin/events.cljs index 39f585d5b596..db3e60def176 100644 --- a/src/status_im/contexts/chat/messenger/messages/pin/events.cljs +++ b/src/status_im/contexts/chat/messenger/messages/pin/events.cljs @@ -97,7 +97,7 @@ (rf/defn send-pin-message "Pin message, rebuild pinned messages list" {:events [:pin-message/send-pin-message]} - [{:keys [db] :as cofx} {:keys [chat-id message-id pinned remote-only?] :as pin-message}] + [cofx {:keys [remote-only?] :as pin-message}] (rf/merge cofx (when-not remote-only? (send-pin-message-locally pin-message)) (data-store.pin-messages/send-pin-message {:chat-id (pin-message :chat-id) diff --git a/src/status_im/contexts/chat/messenger/messages/transport/events.cljs b/src/status_im/contexts/chat/messenger/messages/transport/events.cljs index 3b5941773765..f96d9c535d50 100644 --- a/src/status_im/contexts/chat/messenger/messages/transport/events.cljs +++ b/src/status_im/contexts/chat/messenger/messages/transport/events.cljs @@ -34,7 +34,7 @@ (rf/defn process-response {:events [:process-response]} - [{:keys [db] :as cofx} ^js response-js process-async] + [cofx ^js response-js process-async] (let [^js communities (.-communities response-js) ^js requests-to-join-community (.-requestsToJoinCommunity response-js) ^js chats (.-chats response-js) @@ -291,7 +291,7 @@ [{:keys [db] :as cofx} ^js response-js process-async] (when response-js (let [current-chat-id (:current-chat-id db) - {:keys [db messages transactions chats statuses]} + {:keys [db messages transactions statuses]} (reduce group-by-and-update-unviewed-counts {:db db :chats #{} @@ -343,7 +343,7 @@ [{:keys [db] :as cofx} message-id status] (if-let [{:keys [chat-id]} (get-in db [:transport/message-envelopes message-id])] - (when-let [{:keys [from]} (get-in db [:messages chat-id message-id])] + (when-let [{:keys [_from]} (get-in db [:messages chat-id message-id])] (check-confirmations cofx status chat-id message-id)) ;; We don't have a message-envelope for this, might be that the confirmation came too early {:db (update-in db [:transport/message-confirmations message-id] conj status)})) diff --git a/src/status_im/contexts/chat/messenger/photo_selector/events.cljs b/src/status_im/contexts/chat/messenger/photo_selector/events.cljs index 2b8357fe4af1..5af1decbf494 100644 --- a/src/status_im/contexts/chat/messenger/photo_selector/events.cljs +++ b/src/status_im/contexts/chat/messenger/photo_selector/events.cljs @@ -14,8 +14,8 @@ (rf/defn get-photos-count-ios {:events [:on-camera-roll-get-images-count-ios]} - [{:keys [db]} count] - {:db (assoc db :camera-roll/ios-images-count count)}) + [{:keys [db]} cnt] + {:db (assoc db :camera-roll/ios-images-count cnt)}) (rf/defn camera-roll-get-albums {:events [:photo-selector/camera-roll-get-albums]} diff --git a/src/status_im/contexts/chat/messenger/photo_selector/style.cljs b/src/status_im/contexts/chat/messenger/photo_selector/style.cljs index 6bffc473bbc9..794e38d879a9 100644 --- a/src/status_im/contexts/chat/messenger/photo_selector/style.cljs +++ b/src/status_im/contexts/chat/messenger/photo_selector/style.cljs @@ -24,37 +24,6 @@ {:position :absolute :right 20}) -(defn close-button-container - [theme] - {:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme) - :width 32 - :height 32 - :border-radius 10 - :justify-content :center - :align-items :center - :position :absolute - :left 20}) - -(defn title-container - [theme] - {:flex-direction :row - :background-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme) - :border-radius 10 - :padding-horizontal 12 - :padding-vertical 5 - :align-self :center}) - -(defn chevron-container - [theme] - {:background-color (colors/theme-colors colors/neutral-30 colors/neutral-100 theme) - :width 14 - :height 14 - :border-radius 7 - :justify-content :center - :align-items :center - :margin-left 7 - :margin-top 4}) - (defn image [window-width index] {:width (- (/ window-width 3) 0.67) diff --git a/src/status_im/contexts/communities/actions/accounts_selection/events_test.cljs b/src/status_im/contexts/communities/actions/accounts_selection/events_test.cljs index 94f0d3367403..31a0d24bebfb 100644 --- a/src/status_im/contexts/communities/actions/accounts_selection/events_test.cljs +++ b/src/status_im/contexts/communities/actions/accounts_selection/events_test.cljs @@ -29,20 +29,6 @@ :color :pink :emoji "🦩"}}) -(def permissioned-accounts - [{:address "0xB" - :position 0 - :color :blue - :emoji "🐈" - :airdrop-address? true - :reveal? true} - {:address "0xC" - :position 1 - :color :orange - :emoji "🛏️" - :airdrop-address? false - :reveal? false}]) - (deftest initialize-permission-addresses-test (testing "fetches revealed accounts when joined" (let [cofx {:db {:communities {community-id {:joined true}}}}] diff --git a/src/status_im/contexts/communities/actions/share_community_channel/style.cljs b/src/status_im/contexts/communities/actions/share_community_channel/style.cljs index e1d620502c60..df81455e9934 100644 --- a/src/status_im/contexts/communities/actions/share_community_channel/style.cljs +++ b/src/status_im/contexts/communities/actions/share_community_channel/style.cljs @@ -20,18 +20,3 @@ :margin-top 8 :align-items :center}) -(def gradient-cover-padding 20) -(def qr-code-padding 12) - -(defn qr-code-size - [total-width] - (- total-width (* gradient-cover-padding 2) (* qr-code-padding 2))) - -(defn gradient-cover-size - [total-width] - (- total-width (* gradient-cover-padding 2))) - -(defn gradient-cover-wrapper - [width] - {:width (gradient-cover-size width) - :border-radius 12}) diff --git a/src/status_im/contexts/communities/events.cljs b/src/status_im/contexts/communities/events.cljs index ebde6f3ab479..1edfd26cee12 100644 --- a/src/status_im/contexts/communities/events.cljs +++ b/src/status_im/contexts/communities/events.cljs @@ -71,7 +71,7 @@ (rf/defn handle-communities {:events [:community/fetch-success]} - [{:keys [db]} communities-js] + [_ communities-js] {:fx (map (fn [c] [:dispatch [:communities/handle-community c]]) communities-js)}) diff --git a/src/status_im/contexts/communities/home/style.cljs b/src/status_im/contexts/communities/home/style.cljs deleted file mode 100644 index 241030ed3934..000000000000 --- a/src/status_im/contexts/communities/home/style.cljs +++ /dev/null @@ -1,64 +0,0 @@ -(ns status-im.contexts.communities.home.style - (:require - [quo.foundations.colors :as colors] - [react-native.platform :as platform] - [react-native.reanimated :as reanimated] - [react-native.safe-area :as safe-area])) - -(def tabs - {:padding-horizontal 20 - :padding-top 8 - :padding-bottom 12}) - -(def blur - {:position :absolute - :top 0 - :right 0 - :left 0 - :bottom 0}) - -(def empty-state-placeholder - {:height 120 - :width 120 - :background-color colors/danger-50}) - -(defn blur-banner-layer - [animated-translation-y] - (let [fixed-height (+ (safe-area/get-top) 244)] - (reanimated/apply-animations-to-style - {:transform [{:translate-y animated-translation-y}]} - {:overflow (if platform/ios? :visible :hidden) - :z-index 1 - :position :absolute - :top 0 - :right 0 - :left 0 - :height fixed-height}))) - -(defn hiding-banner-layer - [] - {:z-index 2 - :position :absolute - :top 0 - :right 0 - :left 0 - :padding-top (safe-area/get-top)}) - -(defn tabs-banner-layer - [animated-translation-y] - (let [top-offset (+ (safe-area/get-top) 192)] - (reanimated/apply-animations-to-style - {:transform [{:translate-y animated-translation-y}]} - {:z-index 3 - :position :absolute - :top top-offset - :right 0 - :left 0}))) - -(def animated-card-container {:overflow :hidden}) - -(defn animated-card - [opacity translate-y] - (reanimated/apply-animations-to-style {:opacity opacity - :transform [{:translate-y translate-y}]} - {})) diff --git a/src/status_im/contexts/communities/overview/utils.cljs b/src/status_im/contexts/communities/overview/utils.cljs deleted file mode 100644 index bf105b84a7fd..000000000000 --- a/src/status_im/contexts/communities/overview/utils.cljs +++ /dev/null @@ -1,22 +0,0 @@ -(ns status-im.contexts.communities.overview.utils - (:require - [clojure.string :as string] - [utils.i18n :as i18n])) - -(defn join-existing-users-string - [user-list] - (let [users-count (count user-list) - first-two (->> user-list - (take 2) - (map #(string/split (:full-name %) #" ")) - (map first))] - (case users-count - 0 "" - 1 (i18n/label :t/join-one-user {:user (first first-two)}) - 2 (i18n/label :t/join-two-users - {:user1 (first first-two) - :user2 (second first-two)}) - (i18n/label :t/join-more-users - {:user1 (first first-two) - :user2 (second first-two) - :left-count (- users-count 2)})))) diff --git a/src/status_im/contexts/onboarding/create_password/style.cljs b/src/status_im/contexts/onboarding/create_password/style.cljs index 67b5d599fd7e..7efe438b9765 100644 --- a/src/status_im/contexts/onboarding/create_password/style.cljs +++ b/src/status_im/contexts/onboarding/create_password/style.cljs @@ -7,9 +7,6 @@ (def heading-subtitle {:color colors/white}) (def heading-title (assoc heading-subtitle :margin-bottom 8)) -(def info-message - {:margin-top 8}) - (def space-between-inputs {:height 16}) (def password-tips diff --git a/src/status_im/contexts/onboarding/share_usage/style.cljs b/src/status_im/contexts/onboarding/share_usage/style.cljs index 1f8d4012c87c..556034e2de8a 100644 --- a/src/status_im/contexts/onboarding/share_usage/style.cljs +++ b/src/status_im/contexts/onboarding/share_usage/style.cljs @@ -1,11 +1,6 @@ (ns status-im.contexts.onboarding.share-usage.style (:require [quo.foundations.colors :as colors])) -(def title-container - {:margin-horizontal 20 - :padding-bottom 20 - :padding-top 12}) - (defn page-illustration [width] {:flex 1 diff --git a/src/status_im/contexts/onboarding/sign_in/style.cljs b/src/status_im/contexts/onboarding/sign_in/style.cljs deleted file mode 100644 index 71171f6bb122..000000000000 --- a/src/status_im/contexts/onboarding/sign_in/style.cljs +++ /dev/null @@ -1,95 +0,0 @@ -(ns status-im.contexts.onboarding.sign-in.style - (:require - [quo.foundations.colors :as colors])) - -(def screen-padding 20) - -(def flex-spacer {:flex 1}) - -(def absolute-fill - {:position :absolute - :top 0 - :bottom 0 - :left 0 - :right 0}) - -(defn root-container - [padding-top] - {:flex 1 - :padding-top padding-top}) - -(def header-container - {:flex-direction :row - :justify-content :space-between - :padding-horizontal screen-padding - :margin-vertical 12}) - -(def header-text - {:padding-horizontal screen-padding - :padding-top 12 - :padding-bottom 8 - :color colors/white}) - -(def header-sub-text - {:padding-horizontal screen-padding - :color colors/white}) - -(def tabs-container - {:padding-horizontal screen-padding - :margin-top 20}) - -(def scan-qr-code-container - {:margin-top 19}) - -(def qr-view-finder - {:margin-horizontal screen-padding - :height 1 - :display :flex}) - -(defn viewfinder-container - [viewfinder] - {:position :absolute - :left (:x viewfinder) - :top (:y viewfinder)}) - -(def viewfinder-text - {:color colors/white-opa-70 - :text-align :center - :padding-top 16}) - -(def camera-permission-container - {:height 335 - :margin-horizontal screen-padding - :background-color colors/white-opa-5 - :border-color colors/white-opa-10 - :border-radius 12 - :border-style :dashed - :border-width 1 - :align-items :center - :justify-content :center}) - -(def enable-camera-access-header - {:color colors/white}) - -(def enable-camera-access-sub-text - {:color colors/white-opa-70 - :margin-bottom 16}) - -(def enter-sync-code-container - {:margin-top 20 - :justify-content :center - :align-items :center}) - -(defn bottom-container - [padding-bottom] - {:padding-top 12 - :padding-bottom padding-bottom - :background-color colors/white-opa-5 - :border-top-left-radius 20 - :border-top-right-radius 20 - :align-items :center - :justify-content :center}) - -(def bottom-text - {:color colors/white - :padding-bottom 12}) diff --git a/src/status_im/contexts/preview/quo/preview.clj b/src/status_im/contexts/preview/quo/preview.clj deleted file mode 100644 index a8d9d7f46d5a..000000000000 --- a/src/status_im/contexts/preview/quo/preview.clj +++ /dev/null @@ -1,10 +0,0 @@ -(ns status-im.contexts.preview.quo.preview) - -(defmacro list-comp - [[the-binding seq-expr & bindings] body-expr] - (cond (not the-binding) - `(list ~body-expr) - - :else - `(mapcat (fn [~the-binding] (list-comp ~bindings ~body-expr)) - ~seq-expr))) diff --git a/src/status_im/contexts/preview/quo/preview.cljs b/src/status_im/contexts/preview/quo/preview.cljs index f00afea65fa5..c63c67daef39 100644 --- a/src/status_im/contexts/preview/quo/preview.cljs +++ b/src/status_im/contexts/preview/quo/preview.cljs @@ -14,8 +14,7 @@ [status-im.contexts.preview.quo.common :as common] [status-im.contexts.preview.quo.style :as style] utils.number - [utils.re-frame :as rf]) - (:require-macros status-im.contexts.preview.quo.preview)) + [utils.re-frame :as rf])) (defn- label-view [_ label theme] diff --git a/src/status_im/contexts/preview/quo/tabs/account_selector.cljs b/src/status_im/contexts/preview/quo/tabs/account_selector.cljs index b1efa83ef87b..52826b948e4e 100644 --- a/src/status_im/contexts/preview/quo/tabs/account_selector.cljs +++ b/src/status_im/contexts/preview/quo/tabs/account_selector.cljs @@ -10,33 +10,6 @@ {:key :account-text :type :text} {:key :label-text :type :text}]) -;; keeping this unused data structure in the code for now -;; will reference them when I introduce multiple account support -;; and allow passing lists of accounts instead of just 1 account -(def single-account - [{:account-text "My Savings" - :account-emoji "🍑" - :label-text "Label"}]) - -(def two-accounts - [{:account-text "My Savings" - :account-emoji "🍑" - :label-text "Label"} - {:account-text "My Current" - :account-emoji "🍎" - :label-text "Label 2"}]) - -(def many-accounts - [{:account-text "My Savings" - :account-emoji "🍑" - :label-text "Label"} - {:account-text "My Current" - :account-emoji "🍎" - :label-text "Label 2"} - {:account-text "My Reimbursment" - :account-emoji "🍟" - :label-text "Label 3"}]) - (defn view [] (let [state (reagent/atom {:show-label? true diff --git a/src/status_im/contexts/profile/push_notifications/events.cljs b/src/status_im/contexts/profile/push_notifications/events.cljs index f527b862db82..ca301e0fd565 100644 --- a/src/status_im/contexts/profile/push_notifications/events.cljs +++ b/src/status_im/contexts/profile/push_notifications/events.cljs @@ -13,9 +13,6 @@ [utils.re-frame :as rf] [utils.transforms :as transforms])) -(def server-type-default 1) -(def server-type-custom 2) - (def apn-token-type 1) (def firebase-token-type 2) @@ -39,7 +36,7 @@ {:events [:push-notifications/registered-for-push-notifications]} [_ token] {:json-rpc/call [{:method "wakuext_registerForPushNotifications" - :params [token (if platform/ios? config/apn-topic) + :params [token (when platform/ios? config/apn-topic) (if platform/ios? apn-token-type firebase-token-type)] :on-success #(log/info "[push-notifications] register-success" %) :on-error #(log/info "[push-notifications] register-error" %)}]}) diff --git a/src/status_im/contexts/profile/settings/header/style.cljs b/src/status_im/contexts/profile/settings/header/style.cljs index eb1f510dff3c..2a2bff1b0720 100644 --- a/src/status_im/contexts/profile/settings/header/style.cljs +++ b/src/status_im/contexts/profile/settings/header/style.cljs @@ -1,5 +1,4 @@ -(ns status-im.contexts.profile.settings.header.style - (:require [quo.foundations.colors :as colors])) +(ns status-im.contexts.profile.settings.header.style) (def avatar-row-wrapper {:display :flex @@ -22,14 +21,3 @@ {:opacity opacity-animation :flex-direction :row :justify-content :space-between}) - -(defn avatar-container - [theme scale-animation top-margin-animation side-margin-animation] - [{:transform [{:scale scale-animation}] - :margin-top top-margin-animation - :margin-left side-margin-animation - :margin-bottom side-margin-animation} - {:align-items :flex-start - :border-width 4 - :border-color (colors/theme-colors colors/border-avatar-light colors/neutral-80-opa-80 theme) - :border-radius 100}]) diff --git a/src/status_im/contexts/profile/settings/screens/password/change_password/style.cljs b/src/status_im/contexts/profile/settings/screens/password/change_password/style.cljs index ceee6c82b58c..3754438f5a04 100644 --- a/src/status_im/contexts/profile/settings/screens/password/change_password/style.cljs +++ b/src/status_im/contexts/profile/settings/screens/password/change_password/style.cljs @@ -15,9 +15,6 @@ (def heading-title (assoc heading-subtitle :margin-bottom 8)) -(def info-message - {:margin-top 8}) - (def space-between-inputs {:height 16}) (def error-container diff --git a/src/status_im/contexts/profile/settings/screens/password/style.cljs b/src/status_im/contexts/profile/settings/screens/password/style.cljs index f66a212dadb2..81f1340f8031 100644 --- a/src/status_im/contexts/profile/settings/screens/password/style.cljs +++ b/src/status_im/contexts/profile/settings/screens/password/style.cljs @@ -1,10 +1 @@ (ns status-im.contexts.profile.settings.screens.password.style) - -(defn navigation - [top-inset] - {:padding-top top-inset}) - -(def header - {:padding-horizontal 20 - :padding-bottom 8 - :padding-top 12}) diff --git a/src/status_im/contexts/settings/wallet/network_settings/style.cljs b/src/status_im/contexts/settings/wallet/network_settings/style.cljs index c33de067040a..f4b31906d30b 100644 --- a/src/status_im/contexts/settings/wallet/network_settings/style.cljs +++ b/src/status_im/contexts/settings/wallet/network_settings/style.cljs @@ -1,5 +1,4 @@ -(ns status-im.contexts.settings.wallet.network-settings.style - (:require [quo.foundations.colors :as colors])) +(ns status-im.contexts.settings.wallet.network-settings.style) (def title-container {:flex 0 @@ -21,6 +20,3 @@ (def advanced-settings-container {:flex-shrink 0}) - -(def testnet-not-available - {:color colors/danger-60}) diff --git a/src/status_im/contexts/shell/activity_center/events.cljs b/src/status_im/contexts/shell/activity_center/events.cljs index d68f16bdd456..7bd5f0e58fb7 100644 --- a/src/status_im/contexts/shell/activity_center/events.cljs +++ b/src/status_im/contexts/shell/activity_center/events.cljs @@ -216,7 +216,7 @@ (rf/defn accept-notification {:events [:activity-center.notifications/accept]} - [{:keys [db]} notification-id] + [_ notification-id] {:json-rpc/call [{:method "wakuext_acceptActivityCenterNotifications" :params [[notification-id]] :on-success [:activity-center.notifications/accept-success notification-id] @@ -234,7 +234,7 @@ (rf/defn dismiss-notification {:events [:activity-center.notifications/dismiss]} - [{:keys [db]} notification-id] + [_ notification-id] {:json-rpc/call [{:method "wakuext_dismissActivityCenterNotifications" :params [[notification-id]] :on-success [:activity-center.notifications/dismiss-success notification-id] @@ -249,7 +249,7 @@ (rf/defn delete-notification {:events [:activity-center.notifications/delete]} - [{:keys [db]} notification-id] + [_ notification-id] {:json-rpc/call [{:method "wakuext_deleteActivityCenterNotifications" :params [[notification-id]] :on-success [:activity-center.notifications/delete-success notification-id] @@ -310,19 +310,10 @@ (and (some? cursor) (not= cursor start-or-end-cursor))) -(def ^:const status-unread 2) -(def ^:const status-all 3) (def ^:const read-type-read 1) (def ^:const read-type-unread 2) (def ^:const read-type-all 3) -(defn status - [filter-status] - (case filter-status - :unread status-unread - :all status-all - 99)) - (defn ->rpc-read-type [read-type] (case read-type @@ -528,7 +519,7 @@ {:events [:activity-center.notifications/show-toasts]} [{:keys [db]} new-notifications] (let [my-public-key (get-in db [:profile/profile :public-key])] - (reduce (fn [cofx {:keys [author chat-id type accepted dismissed message name] :as x}] + (reduce (fn [cofx {:keys [author chat-id type accepted dismissed message name]}] (let [user-avatar {:full-name name :status-indicator? true :online? nil diff --git a/src/status_im/contexts/shell/activity_center/events_test.cljs b/src/status_im/contexts/shell/activity_center/events_test.cljs index 32f8100fc160..6df16a4d86bf 100644 --- a/src/status_im/contexts/shell/activity_center/events_test.cljs +++ b/src/status_im/contexts/shell/activity_center/events_test.cljs @@ -2,7 +2,6 @@ (:require [cljs.test :refer [deftest is testing]] matcher-combinators.test - [status-im.constants :as constants] [status-im.contexts.shell.activity-center.events :as events] [status-im.contexts.shell.activity-center.notification-types :as types] [test-helpers.unit :as h])) @@ -161,49 +160,6 @@ ;;;; Contact verification -(def contact-verification-rpc-response - {:activityCenterNotifications - [{:accepted false - :author "0x04d03f" - :chatId "0x04d03f" - :contactVerificationStatus constants/contact-verification-status-pending - :dismissed false - :id notification-id - :message {} - :name "0x04d03f" - :read true - :timestamp 1666647286000 - :type types/contact-verification}]}) - -(def contact-verification-expected-notification - {:accepted false - :author "0x04d03f" - :chat-id "0x04d03f" - :contact-verification-status constants/contact-verification-status-pending - :dismissed false - :id notification-id - :last-message nil - :message {:command-parameters nil - :content {:chat-id nil - :ens-name nil - :image nil - :line-count nil - :links nil - :parsed-text nil - :response-to nil - :rtl? nil - :sticker nil - :text nil} - :outgoing false - :outgoing-status nil - :link-previews [] - :quoted-message nil} - :name "0x04d03f" - :read true - :reply-message nil - :timestamp 1666647286000 - :type types/contact-verification}) - (deftest contact-verification-decline-test (is (match? {:json-rpc/call [{:method "wakuext_declineContactVerificationRequest" diff --git a/src/status_im/contexts/shell/activity_center/notification/common/style.cljs b/src/status_im/contexts/shell/activity_center/notification/common/style.cljs index b1ce7a44da98..f0613ffc1ffa 100644 --- a/src/status_im/contexts/shell/activity_center/notification/common/style.cljs +++ b/src/status_im/contexts/shell/activity_center/notification/common/style.cljs @@ -6,9 +6,6 @@ (def swipe-button-border-radius 16) (def swipe-button-margin 8) -(def user-avatar-tag - {:background-color colors/white-opa-10}) - (def user-avatar-tag-text {:color colors/white}) diff --git a/src/status_im/contexts/shell/activity_center/notification/mentions/style.cljs b/src/status_im/contexts/shell/activity_center/notification/mentions/style.cljs index 195eebb8404a..f1d2f95ae1e7 100644 --- a/src/status_im/contexts/shell/activity_center/notification/mentions/style.cljs +++ b/src/status_im/contexts/shell/activity_center/notification/mentions/style.cljs @@ -2,9 +2,6 @@ (:require [quo.foundations.colors :as colors])) -(def tag - {:background-color colors/white-opa-10}) - (def tag-text {:color colors/white}) diff --git a/src/status_im/contexts/shell/activity_center/notification/reply/style.cljs b/src/status_im/contexts/shell/activity_center/notification/reply/style.cljs index bee0c602c50e..a61f5d3dae87 100644 --- a/src/status_im/contexts/shell/activity_center/notification/reply/style.cljs +++ b/src/status_im/contexts/shell/activity_center/notification/reply/style.cljs @@ -2,9 +2,6 @@ (:require [quo.foundations.colors :as colors])) -(def tag - {:background-color colors/white-opa-10}) - (def tag-text {:color colors/white}) diff --git a/src/status_im/contexts/shell/activity_center/style.cljs b/src/status_im/contexts/shell/activity_center/style.cljs index eba8ab117715..168c8dd379f3 100644 --- a/src/status_im/contexts/shell/activity_center/style.cljs +++ b/src/status_im/contexts/shell/activity_center/style.cljs @@ -40,21 +40,3 @@ :flex 1 :justify-content :center :padding-bottom 20}) - -(def empty-title - {:padding-bottom 2 - :color colors/white}) - -(def empty-subtitle - {:color colors/white}) - -(def empty-rectangle-placeholder - {:width 120 - :height 120 - :background-color colors/danger-50 - :margin-bottom 20}) - -(def blur - {:style {:position :absolute :top 0 :left 0 :right 0 :bottom 0} - :overlayColor colors/neutral-80-opa-80-blur - :blur-amount 20}) diff --git a/src/status_im/contexts/shell/share/events.cljs b/src/status_im/contexts/shell/share/events.cljs index cce601a810f6..40fe18f6898f 100644 --- a/src/status_im/contexts/shell/share/events.cljs +++ b/src/status_im/contexts/shell/share/events.cljs @@ -5,7 +5,7 @@ (rf/defn copy-text-and-show-toast {:events [:share/copy-text-and-show-toast]} - [{:keys [db] :as cofx} {:keys [text-to-copy post-copy-message]}] + [cofx {:keys [text-to-copy post-copy-message]}] (rf/merge cofx {:copy-to-clipboard text-to-copy} (toasts/upsert diff --git a/src/status_im/contexts/shell/share/style.cljs b/src/status_im/contexts/shell/share/style.cljs index 0249da936f36..64d38c7ae1d2 100644 --- a/src/status_im/contexts/shell/share/style.cljs +++ b/src/status_im/contexts/shell/share/style.cljs @@ -33,26 +33,9 @@ :justify-content :flex-start :align-items :flex-start}) -(def profile-address-column - {:flex-direction :column}) - (def emoji-address-column {:flex-direction :column}) -(def profile-address-label - {:color colors/white-opa-40 - :padding-top 10}) - -(def profile-address-content - {:color colors/white - :align-self :flex-start - :padding-top 2}) - -(def profile-address-container - {:flex-direction :row - :justify-content :flex-start - :margin-top 4}) - (def emoji-address-container {:flex-direction :row :justify-content :flex-start}) @@ -63,12 +46,6 @@ :padding-bottom (if platform/ios? 2 0) :padding-left 12}) - -(def share-button-container - {:position :absolute - :right 0 - :top 12}) - (def emoji-share-button-container {:position :absolute :right 0 @@ -87,6 +64,4 @@ :margin-top 8 :margin-bottom 16}) -(def wip-style - {:color colors/white - :text-align :center}) + diff --git a/src/status_im/contexts/syncing/enter_sync_code/style.cljs b/src/status_im/contexts/syncing/enter_sync_code/style.cljs index 783a542657c2..350484ef88ee 100644 --- a/src/status_im/contexts/syncing/enter_sync_code/style.cljs +++ b/src/status_im/contexts/syncing/enter_sync_code/style.cljs @@ -31,11 +31,6 @@ :color colors/white :text-align-vertical :top})) -(def label-texts-container - {:flex-direction :row - :height 18 - :margin-bottom 8}) - (def button-paste {:margin-top 8}) diff --git a/src/status_im/contexts/syncing/events.cljs b/src/status_im/contexts/syncing/events.cljs index 10d5f74a3fac..2d388b5c0b0f 100644 --- a/src/status_im/contexts/syncing/events.cljs +++ b/src/status_im/contexts/syncing/events.cljs @@ -20,7 +20,7 @@ (rf/defn local-pairing-clear-states {:events [:syncing/clear-states]} - [{:keys [db]} role] + [{:keys [db]}] {:db (dissoc db :syncing)}) (defn- input-connection-string-callback @@ -82,7 +82,7 @@ (rf/defn initiate-local-pairing-with-connection-string {:events [:syncing/input-connection-string-for-bootstrapping]} - [{:keys [db]} connection-string] + [_ connection-string] (let [config-map (.stringify js/JSON (clj->js {:receiverConfig @@ -95,7 +95,7 @@ (rf/defn preparations-for-connection-string {:events [:syncing/get-connection-string]} - [{:keys [db] :as cofx} sha3-pwd on-valid-connection-string] + [{:keys [db]} sha3-pwd on-valid-connection-string] (let [error (get-in db [:profile/login :error]) handle-connection (fn [response] (when (sync-utils/valid-connection-string? response) diff --git a/src/status_im/contexts/syncing/setup_syncing/style.cljs b/src/status_im/contexts/syncing/setup_syncing/style.cljs index a176a465ceb0..de8b09300c78 100644 --- a/src/status_im/contexts/syncing/setup_syncing/style.cljs +++ b/src/status_im/contexts/syncing/setup_syncing/style.cljs @@ -18,9 +18,6 @@ :align-items :center :justify-content :space-between}) -(def navigation-bar - {:height 56}) - (def sync-code {:margin-top 20}) diff --git a/src/status_im/contexts/syncing/syncing_devices_list/style.cljs b/src/status_im/contexts/syncing/syncing_devices_list/style.cljs index 185d5ad9bbbb..590e69819759 100644 --- a/src/status_im/contexts/syncing/syncing_devices_list/style.cljs +++ b/src/status_im/contexts/syncing/syncing_devices_list/style.cljs @@ -2,12 +2,6 @@ (:require [quo.foundations.colors :as colors])) -(defn container-main - [top] - {:background-color colors/neutral-95 - :padding-top top - :flex 1}) - (def page-container {:flex 1 :padding-horizontal 20}) diff --git a/src/status_im/contexts/syncing/utils.cljs b/src/status_im/contexts/syncing/utils.cljs index 11910541e079..6d6171a43281 100644 --- a/src/status_im/contexts/syncing/utils.cljs +++ b/src/status_im/contexts/syncing/utils.cljs @@ -1,8 +1,7 @@ (ns status-im.contexts.syncing.utils (:require [clojure.string :as string] - [native-module.core :as native-module] - [utils.transforms :as transforms])) + [native-module.core :as native-module])) (defn validate-connection-string [connection-string] @@ -14,10 +13,3 @@ (some-> connection-string validate-connection-string string/blank?)) - -(defn extract-error - [json-str] - (-> json-str - transforms/json->clj - (get :error "") - not-empty)) diff --git a/src/status_im/contexts/wallet/account/style.cljs b/src/status_im/contexts/wallet/account/style.cljs index 20d6acad850f..b78b17499f70 100644 --- a/src/status_im/contexts/wallet/account/style.cljs +++ b/src/status_im/contexts/wallet/account/style.cljs @@ -13,7 +13,3 @@ {:padding-top 60 :margin-bottom 12 :padding-horizontal 20}) - -(def shell-button - {:position :absolute - :bottom 12}) diff --git a/src/status_im/contexts/wallet/add_account/create_account/new_keypair/confirm_backup/style.cljs b/src/status_im/contexts/wallet/add_account/create_account/new_keypair/confirm_backup/style.cljs index 1bae808bb060..656683282a1c 100644 --- a/src/status_im/contexts/wallet/add_account/create_account/new_keypair/confirm_backup/style.cljs +++ b/src/status_im/contexts/wallet/add_account/create_account/new_keypair/confirm_backup/style.cljs @@ -1,9 +1,5 @@ (ns status-im.contexts.wallet.add-account.create-account.new-keypair.confirm-backup.style) -(def header-container - {:margin-horizontal 20 - :margin-vertical 12}) - (def buttons-container {:padding-horizontal 20 :padding-vertical 12 diff --git a/src/status_im/contexts/wallet/add_account/create_account/style.cljs b/src/status_im/contexts/wallet/add_account/create_account/style.cljs index 0af2fdfbf506..2784cff0df4a 100644 --- a/src/status_im/contexts/wallet/add_account/create_account/style.cljs +++ b/src/status_im/contexts/wallet/add_account/create_account/style.cljs @@ -26,8 +26,4 @@ :padding-bottom 4 :padding-horizontal 20}) -(def divider-line - {:margin-top 12 - :margin-bottom 8}) - (def slide-button-container {:z-index 1}) diff --git a/src/status_im/contexts/wallet/bridge/select_asset/style.cljs b/src/status_im/contexts/wallet/bridge/select_asset/style.cljs index 159c316f2044..4de398e134fc 100644 --- a/src/status_im/contexts/wallet/bridge/select_asset/style.cljs +++ b/src/status_im/contexts/wallet/bridge/select_asset/style.cljs @@ -4,7 +4,3 @@ {:padding-horizontal 20 :padding-vertical 8}) -(def list-content-container - {:padding-horizontal 8 - :padding-top 4 - :padding-bottom 8}) diff --git a/src/status_im/contexts/wallet/common/activity_tab/constants.cljs b/src/status_im/contexts/wallet/common/activity_tab/constants.cljs index 1342c24f1575..67da50f67265 100644 --- a/src/status_im/contexts/wallet/common/activity_tab/constants.cljs +++ b/src/status_im/contexts/wallet/common/activity_tab/constants.cljs @@ -1,16 +1,9 @@ (ns status-im.contexts.wallet.common.activity-tab.constants) -(def ^:const wallet-activity-error-code-success 1) -(def ^:const wallet-activity-error-code-task-canceled 2) -(def ^:const wallet-activity-error-code-failed 3) - (def ^:const wallet-activity-type-send 0) (def ^:const wallet-activity-type-receive 1) -(def ^:const wallet-activity-type-buy 2) (def ^:const wallet-activity-type-swap 3) (def ^:const wallet-activity-type-bridge 4) -(def ^:const wallet-activity-type-contract-deployment 5) -(def ^:const wallet-activity-type-mint 6) (def ^:const wallet-activity-type-approval 7) (def ^:const wallet-activity-status-failed 0) @@ -18,47 +11,11 @@ (def ^:const wallet-activity-status-confirmed 2) (def ^:const wallet-activity-status-finalised 3) -(def ^:const wallet-activity-token-type-native 0) -(def ^:const wallet-activity-token-type-erc-20 1) (def ^:const wallet-activity-token-type-erc-721 2) (def ^:const wallet-activity-token-type-erc-1155 3) -(def ^:const wallet-activity-id->name - {wallet-activity-type-send :send - wallet-activity-type-receive :receive - wallet-activity-type-buy :buy - wallet-activity-type-swap :swap - wallet-activity-type-bridge :bridge - wallet-activity-type-contract-deployment :contract-deployment - wallet-activity-type-mint :mint}) - (def ^:const wallet-activity-status->name {wallet-activity-status-failed :failed wallet-activity-status-pending :pending wallet-activity-status-confirmed :confirmed wallet-activity-status-finalised :finalised}) - -(def ^:const second-tag-prefix - {wallet-activity-type-send :t/from - wallet-activity-type-receive :t/from - wallet-activity-type-buy :t/on - wallet-activity-type-swap :t/to - wallet-activity-type-bridge :t/from - wallet-activity-type-contract-deployment :t/via - wallet-activity-type-mint :t/at}) - -(def ^:const third-tag-prefix - {wallet-activity-type-send :t/to - wallet-activity-type-receive :t/to - wallet-activity-type-buy :t/to - wallet-activity-type-swap :t/on - wallet-activity-type-bridge :t/to - wallet-activity-type-contract-deployment :t/on - wallet-activity-type-mint :t/via}) - -(def ^:const fourth-tag-prefix - {wallet-activity-type-send :t/via - wallet-activity-type-receive :t/via - wallet-activity-type-buy :t/via - wallet-activity-type-swap :t/via - wallet-activity-type-bridge :t/in}) diff --git a/src/status_im/contexts/wallet/common/screen_base/create_or_edit_account/style.cljs b/src/status_im/contexts/wallet/common/screen_base/create_or_edit_account/style.cljs index de8ae531a74e..7c86a3539bbd 100644 --- a/src/status_im/contexts/wallet/common/screen_base/create_or_edit_account/style.cljs +++ b/src/status_im/contexts/wallet/common/screen_base/create_or_edit_account/style.cljs @@ -1,10 +1,4 @@ -(ns status-im.contexts.wallet.common.screen-base.create-or-edit-account.style - (:require [quo.foundations.colors :as colors])) - -(defn root-container - [top] - {:flex 1 - :margin-top top}) +(ns status-im.contexts.wallet.common.screen-base.create-or-edit-account.style) (def account-avatar-container {:padding-horizontal 20 @@ -37,10 +31,3 @@ (def divider-2 {:margin-top 4 :margin-bottom 12}) - -(defn bottom-action - [{:keys [bottom theme]}] - {:padding-horizontal 20 - :padding-vertical 12 - :background-color (colors/theme-colors colors/white colors/neutral-100 theme) - :margin-bottom bottom}) diff --git a/src/status_im/contexts/wallet/common/utils.cljs b/src/status_im/contexts/wallet/common/utils.cljs index 69da2c00c7af..496facc42db5 100644 --- a/src/status_im/contexts/wallet/common/utils.cljs +++ b/src/status_im/contexts/wallet/common/utils.cljs @@ -1,11 +1,9 @@ (ns status-im.contexts.wallet.common.utils (:require [clojure.string :as string] - [native-module.core :as native-module] [quo.foundations.resources :as resources] [status-im.common.qr-codes.view :as qr-codes] [status-im.constants :as constants] [status-im.contexts.wallet.common.utils.networks :as network-utils] - [utils.hex :as utils.hex] [utils.money :as money] [utils.number :as number] [utils.string])) @@ -414,133 +412,6 @@ (let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)] (sort-by (juxt (comp - :balance) priority) tokens))) -(defn- transaction-data - [{:keys [from-address to-address token-address route data eth-transfer?]}] - (let [{:keys [amount-in gas-amount gas-fees]} route - eip-1559-enabled? (:eip-1559-enabled gas-fees) - {:keys [gas-price max-fee-per-gas-medium - max-priority-fee-per-gas]} gas-fees] - (cond-> {:From from-address - :To (or token-address to-address) - :Gas (money/to-hex gas-amount) - :Value (when eth-transfer? amount-in) - :Nonce nil - :Input "" - :Data (or data "0x")} - eip-1559-enabled? (assoc - :TxType "0x02" - :MaxFeePerGas - (money/to-hex - (money/->wei - :gwei - max-fee-per-gas-medium)) - :MaxPriorityFeePerGas - (money/to-hex - (money/->wei - :gwei - max-priority-fee-per-gas))) - (not eip-1559-enabled?) (assoc :TxType "0x00" - :GasPrice - (money/to-hex - (money/->wei - :gwei - gas-price)))))) - -(defn approval-path - [{:keys [route from-address to-address token-address]}] - (let [{:keys [from]} route - from-chain-id (:chain-id from) - approval-amount-required (:approval-amount-required route) - approval-amount-required-sanitized (-> approval-amount-required - (utils.hex/normalize-hex) - (money/from-hex)) - approval-contract-address (:approval-contract-address route) - data (native-module/encode-function-call - constants/contract-function-signature-erc20-approve - [approval-contract-address - approval-amount-required-sanitized]) - tx-data (transaction-data {:from-address from-address - :to-address to-address - :token-address token-address - :route route - :data data - :eth-transfer? false})] - {:BridgeName constants/bridge-name-transfer - :ChainID from-chain-id - :TransferTx tx-data})) - -(defn transaction-path - [{:keys [from-address to-address token-id-from token-address token-id-to route data - slippage-percentage eth-transfer?]}] - (let [{:keys [bridge-name amount-in from - to]} route - tx-data (transaction-data {:from-address from-address - :to-address to-address - :token-address token-address - :route route - :data data - :eth-transfer? eth-transfer?}) - bonder-fees (-> route :bounder-fees money/to-string) - to-chain-id (:chain-id to) - from-chain-id (:chain-id from)] - (cond-> {:BridgeName bridge-name - :ChainID from-chain-id} - - (= bridge-name constants/bridge-name-erc-721-transfer) - (assoc :ERC721TransferTx - (assoc tx-data - :Recipient to-address - :TokenID token-id-from - :ChainID to-chain-id)) - - (= bridge-name constants/bridge-name-erc-1155-transfer) - (assoc :ERC1155TransferTx - (assoc tx-data - :Recipient to-address - :TokenID token-id-from - :ChainID to-chain-id - :Amount amount-in)) - - (= bridge-name constants/bridge-name-transfer) - (assoc :TransferTx tx-data) - - (= bridge-name constants/bridge-name-hop) - (assoc :HopTx - (assoc tx-data - :ChainID from-chain-id - :ChainIDTo to-chain-id - :Symbol token-id-from - :Recipient to-address - :Amount amount-in - :BonderFee bonder-fees)) - - (= bridge-name constants/bridge-name-paraswap) - (assoc :SwapTx - (assoc tx-data - :ChainID from-chain-id - :ChainIDTo to-chain-id - :TokenIDFrom token-id-from - :TokenIDTo token-id-to - :SlippagePercentage slippage-percentage)) - - (= bridge-name constants/bridge-name-celer) - (assoc :CbridgeTx - (assoc tx-data - :ChainID to-chain-id - :Symbol token-id-from - :Recipient to-address - :Amount amount-in))))) - -(defn multi-transaction-command - [{:keys [from-address to-address from-asset to-asset amount-out multi-transaction-type] - :or {multi-transaction-type constants/multi-transaction-type-unknown}}] - {:fromAddress from-address - :toAddress to-address - :fromAsset from-asset - :toAsset to-asset - :fromAmount amount-out - :type multi-transaction-type}) - (defn sort-tokens-by-name [tokens] (let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)] diff --git a/src/status_im/contexts/wallet/common/utils/networks.cljs b/src/status_im/contexts/wallet/common/utils/networks.cljs index 28923cf19376..9938e554c96b 100644 --- a/src/status_im/contexts/wallet/common/utils/networks.cljs +++ b/src/status_im/contexts/wallet/common/utils/networks.cljs @@ -72,19 +72,6 @@ constants/sepolia-chain-ids constants/mainnet-chain-ids)) -(defn resolve-receiver-networks - [{:keys [prefix testnet-enabled?]}] - (let [prefix (if (string/blank? prefix) - constants/default-multichain-address-prefix - prefix) - prefix-seq (string/split prefix #":")] - (->> prefix-seq - (remove string/blank?) - (mapv - #(network->chain-id - {:network % - :testnet-enabled? testnet-enabled?}))))) - (def network->short-name {constants/mainnet-network-name constants/mainnet-short-name constants/optimism-network-name constants/optimism-short-name diff --git a/src/status_im/contexts/wallet/item_types.cljs b/src/status_im/contexts/wallet/item_types.cljs index b7b7502dac49..a8424ec59d1a 100644 --- a/src/status_im/contexts/wallet/item_types.cljs +++ b/src/status_im/contexts/wallet/item_types.cljs @@ -1,13 +1,5 @@ (ns status-im.contexts.wallet.item-types) -(def ^:const no-type 0) -(def ^:const account 1) (def ^:const saved-address 2) (def ^:const address 3) (def ^:const saved-contact-address 4) - -(def ^:const all-supported - #{account - saved-address - address - saved-contact-address}) diff --git a/src/status_im/contexts/wallet/send/input_amount/style.cljs b/src/status_im/contexts/wallet/send/input_amount/style.cljs index 39958ca8169d..3bc1c29bd875 100644 --- a/src/status_im/contexts/wallet/send/input_amount/style.cljs +++ b/src/status_im/contexts/wallet/send/input_amount/style.cljs @@ -1,5 +1,4 @@ -(ns status-im.contexts.wallet.send.input-amount.style - (:require [quo.foundations.colors :as colors])) +(ns status-im.contexts.wallet.send.input-amount.style) (def screen {:flex 1}) @@ -38,24 +37,3 @@ {:height 40 :width "100%" :align-items :center}) - -(defn token-not-available-container - [theme] - {:height 90 - :flex-direction :row - :background-color (colors/resolve-color :danger theme 5) - :border-color (colors/resolve-color :danger theme 10) - :border-width 1 - :border-radius 12 - :margin-horizontal 20 - :padding 12}) - -(def token-not-available-content-container - {:margin-left 8 - :align-items :flex-start}) - -(defn token-not-available-text - [theme] - {:height 36 - :flex 1 - :color (colors/resolve-color :danger theme)}) diff --git a/src/status_im/contexts/wallet/send/select_address/style.cljs b/src/status_im/contexts/wallet/send/select_address/style.cljs index 3cc56aa08d8d..03445e643f30 100644 --- a/src/status_im/contexts/wallet/send/select_address/style.cljs +++ b/src/status_im/contexts/wallet/send/select_address/style.cljs @@ -1,8 +1,5 @@ (ns status-im.contexts.wallet.send.select-address.style) -(def container - {:flex 1}) - (def tabs {:padding-top 20 :padding-bottom 12}) @@ -11,11 +8,6 @@ {:padding-left 20 :padding-right 8}) -(def button - {:justify-self :flex-end - :margin-bottom 20 - :margin-horizontal 20}) - (def network-text-container {:padding-horizontal 12 :padding-top 4}) diff --git a/src/status_im/contexts/wallet/send/select_asset/style.cljs b/src/status_im/contexts/wallet/send/select_asset/style.cljs index 0da8a3d3e52a..3c89588f9fb7 100644 --- a/src/status_im/contexts/wallet/send/select_asset/style.cljs +++ b/src/status_im/contexts/wallet/send/select_asset/style.cljs @@ -6,16 +6,6 @@ {:flex 1 :padding-top (when platform/android? (navigation/status-bar-height))}) -(def title-container - {:margin-horizontal 20 - :margin-vertical 12}) - -(defn empty-container-style - [margin-bottom] - {:justify-content :center - :flex 1 - :margin-bottom margin-bottom}) - (def search-input-container {:padding-horizontal 20 :padding-vertical 8}) diff --git a/src/status_im/contexts/wallet/send/transaction_settings/style.cljs b/src/status_im/contexts/wallet/send/transaction_settings/style.cljs deleted file mode 100644 index 677bca664e41..000000000000 --- a/src/status_im/contexts/wallet/send/transaction_settings/style.cljs +++ /dev/null @@ -1,14 +0,0 @@ -(ns status-im.contexts.wallet.send.transaction-settings.style - (:require - [quo.foundations.colors :as colors])) - -(defn prop-text - [theme] - {:color (colors/theme-colors colors/neutral-100 colors/white theme)}) - -(def content-line - {:flex-direction :row - :margin-top 2 - :align-items :center - :column-gap 4 - :justify-content :flex-start}) diff --git a/src/status_im/contexts/wallet/sheets/account_options/style.cljs b/src/status_im/contexts/wallet/sheets/account_options/style.cljs index d97fabcba7bd..6b6cd276c5db 100644 --- a/src/status_im/contexts/wallet/sheets/account_options/style.cljs +++ b/src/status_im/contexts/wallet/sheets/account_options/style.cljs @@ -21,12 +21,6 @@ :left 0 :right 0}) -(def gradient-container - {:position :absolute - :top 0 - :left 0 - :right 0}) - (def divider-label {:margin-top 8}) diff --git a/src/status_im/contexts/wallet/sheets/unpreferred_networks_alert/style.cljs b/src/status_im/contexts/wallet/sheets/unpreferred_networks_alert/style.cljs deleted file mode 100644 index 505ca2dd1ad3..000000000000 --- a/src/status_im/contexts/wallet/sheets/unpreferred_networks_alert/style.cljs +++ /dev/null @@ -1,10 +0,0 @@ -(ns status-im.contexts.wallet.sheets.unpreferred-networks-alert.style) - -(def sending-to-unpreferred-networks-title - {:margin-horizontal 20}) - -(def sending-to-unpreferred-networks-text - {:flex 1 - :height 66 - :margin-horizontal 20 - :margin-vertical 4}) diff --git a/src/status_im/contexts/wallet/sheets/unpreferred_networks_alert/view.cljs b/src/status_im/contexts/wallet/sheets/unpreferred_networks_alert/view.cljs deleted file mode 100644 index 95358a71f367..000000000000 --- a/src/status_im/contexts/wallet/sheets/unpreferred_networks_alert/view.cljs +++ /dev/null @@ -1,28 +0,0 @@ -(ns status-im.contexts.wallet.sheets.unpreferred-networks-alert.view - (:require [quo.core :as quo] - [re-frame.core :as rf] - [status-im.contexts.wallet.sheets.unpreferred-networks-alert.style :as style] - [utils.i18n :as i18n])) - -(defn view - [{:keys [on-confirm]}] - [:<> - [quo/text - {:style style/sending-to-unpreferred-networks-title - :size :heading-2 - :weight :semi-bold} - (i18n/label :t/sending-to-unpreferred-networks)] - [quo/text - {:style style/sending-to-unpreferred-networks-text - :size :paragraph-1} - (i18n/label :t/sending-to-networks-the-receiver-does-not-prefer)] - [quo/bottom-actions - {:actions :two-actions - :button-two-label (i18n/label :t/cancel) - :button-two-props {:on-press #(rf/dispatch [:hide-bottom-sheet]) - :type :grey} - :button-one-label (i18n/label :t/proceed-anyway) - :button-one-props {:on-press (fn [] - (rf/dispatch [:hide-bottom-sheet]) - (when on-confirm (on-confirm))) - :customization-color :danger}}]]) diff --git a/src/status_im/contexts/wallet/swap/utils.cljs b/src/status_im/contexts/wallet/swap/utils.cljs index 2eb3b36d2746..737f69ddd787 100644 --- a/src/status_im/contexts/wallet/swap/utils.cljs +++ b/src/status_im/contexts/wallet/swap/utils.cljs @@ -1,6 +1,5 @@ (ns status-im.contexts.wallet.swap.utils (:require [status-im.constants :as constants] - [status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils.networks :as network-utils] [utils.i18n :as i18n])) @@ -54,18 +53,6 @@ token networks)))) -(defn select-default-asset-to-receive - "Selects an asset to receive if it was not provided explicitly. - The principle of how the asset is being selected is simple: we get the - whole list, remove the currently selected `asset-to-pay` from it, and choose - the first one of what's left." - [{:keys [wallet account test-networks-enabled? asset-to-pay]}] - (let [networks (-> (get-in wallet [:networks (if test-networks-enabled? :test :prod)]) - (network-utils/sorted-networks-with-details))] - (->> (utils/tokens-with-balance (:tokens account) networks nil) - (remove #(= (:symbol %) (:symbol asset-to-pay))) - first))) - (defn select-network "Chooses the network. Usually user needs to do the selection first and if the selection was done diff --git a/src/status_im/core.cljs b/src/status_im/core.cljs index a4f94ae76955..5e0456bbae6f 100644 --- a/src/status_im/core.cljs +++ b/src/status_im/core.cljs @@ -42,6 +42,8 @@ [] (boolean (.-HermesInternal js/global))) +;; ignore warning: init used in shadow-cljs.edn +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn init [] (status-backend-client/init) diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 3b1f2ee3c444..e1eee0fabfb6 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -8,7 +8,6 @@ status-im.common.image-crop-picker.events [status-im.common.json-rpc.events] status-im.common.log - status-im.common.password-authentication.events status-im.common.peer-stats.events status-im.common.shared-urls.events status-im.common.signals.events diff --git a/src/status_im/feature_flags.cljs b/src/status_im/feature_flags.cljs index 23cde910f085..1d175453fe66 100644 --- a/src/status_im/feature_flags.cljs +++ b/src/status_im/feature_flags.cljs @@ -72,9 +72,3 @@ initial-flags (fn [] (reset! feature-flags-config initial-flags)))) - -(defn alert - [flag action] - (if (enabled? flag) - (action) - (js/alert (str flag " is currently feature flagged off")))) diff --git a/src/status_im/navigation/events.cljs b/src/status_im/navigation/events.cljs index ac0c66312f9e..bbfa7233d285 100644 --- a/src/status_im/navigation/events.cljs +++ b/src/status_im/navigation/events.cljs @@ -44,7 +44,7 @@ (rf/defn dismiss-modal {:events [:dismiss-modal]} - [{:keys [db]} comp-id] + [_ comp-id] {:dismiss-modal comp-id}) (rf/defn navigate-back @@ -57,7 +57,7 @@ (rf/defn navigate-back-to {:events [:navigate-back-to]} - [{:keys [db]} comp-id] + [_ comp-id] {:navigate-back-to comp-id}) (rf/defn pop-to-root @@ -103,7 +103,7 @@ (rf/defn show-next-bottom-sheet {:events [:show-next-bottom-sheet]} - [{:keys [db] :as cofx}] + [{:keys [db]}] {:show-bottom-sheet {:theme (:theme db)}}) (rf/defn show-bottom-sheet diff --git a/src/status_im/setup/hot_reload.cljs b/src/status_im/setup/hot_reload.cljs index 11f6c64f13ba..3c66b276493e 100644 --- a/src/status_im/setup/hot_reload.cljs +++ b/src/status_im/setup/hot_reload.cljs @@ -13,6 +13,8 @@ (defonce visible (reagent/atom false)) (defonce label (reagent/atom "")) +;; ignore warning: reload used in shadow-cljs.edn +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn reload [] (js/setTimeout #(reset! visible false) 500) @@ -25,6 +27,8 @@ (schema.state/clear-errors) (swap! cnt inc)) +;; ignore warning: before-reload used in shadow-cljs.edn +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn before-reload [done] (when @reload-interval (js/clearInterval @reload-interval)) @@ -62,6 +66,8 @@ (reset! label "building") (reset! visible true)) +;; ignore warning: build-notify used in shadow-cljs.edn +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn build-notify [{:keys [type info]}] (cond (= :build-start type) diff --git a/src/status_im/subs/chats.cljs b/src/status_im/subs/chats.cljs index 23df8a6b623b..725a26b7200a 100644 --- a/src/status_im/subs/chats.cljs +++ b/src/status_im/subs/chats.cljs @@ -1,7 +1,6 @@ (ns status-im.subs.chats (:require [clojure.string :as string] - [legacy.status-im.group-chats.db :as group-chats.db] [re-frame.core :as re-frame] [status-im.constants :as constants] [status-im.contexts.chat.events :as chat.events] @@ -53,6 +52,11 @@ (fn [[{:keys [chats]}] [_ community-id chat-id]] (get chats (string/replace chat-id community-id "")))) +(defn member? + [public-key {:keys [members contacts users]}] + (let [members-list (into #{} (concat (keys users) contacts (map #(:id %) members)))] + (contains? members-list public-key))) + (re-frame/reg-sub :chats/home-list-chats :<- [:chats/chats] @@ -61,7 +65,7 @@ (fn [[chats active-chats my-public-key]] (reduce #(if-let [item (get chats %2)] (let [group-chat-member? (and (chat.events/group-chat? item) - (group-chats.db/member? my-public-key item))] + (member? my-public-key item))] (conj %1 (assoc item :group-chat-member? @@ -76,12 +80,6 @@ (fn [chats [_ chat-id]] (get chats chat-id))) -(re-frame/reg-sub - :chats/chat-members-by-id - :<- [:chats/chats] - (fn [chats [_ chat-id]] - (get-in chats [chat-id :members]))) - (re-frame/reg-sub :chats/muted (fn [[_ chat-id] _] @@ -137,7 +135,7 @@ (and (chat.events/group-chat? current-chat) - (group-chats.db/member? my-public-key current-chat)) + (member? my-public-key current-chat)) (assoc :able-to-send-message? true :member? true) @@ -291,13 +289,6 @@ (fn [{:keys [metadata]}] (:editing-message metadata))) -(re-frame/reg-sub - :chats/sending-audio - :<- [:chats/current-chat-id] - :<- [:chat/inputs] - (fn [[chat-id inputs]] - (get-in inputs [chat-id :audio]))) - (defn filter-selected-contacts [selected-contacts contacts] (filter #(:added? (contacts %)) selected-contacts)) @@ -309,12 +300,6 @@ (fn [[selected-contacts contacts]] (count (filter-selected-contacts selected-contacts contacts)))) -(re-frame/reg-sub - :selected-participants-count - :<- [:selected-participants] - (fn [selected-participants] - (count selected-participants))) - (defn filter-contacts [selected-contacts active-contacts] (filter #(selected-contacts (:public-key %)) active-contacts)) @@ -332,13 +317,6 @@ (fn [invitations [_ chat-id]] (filter #(= (:chat-id %) chat-id) (vals invitations)))) -(re-frame/reg-sub - :group-chat/pending-invitations-by-chat-id - (fn [[_ chat-id] _] - [(re-frame/subscribe [:group-chat/invitations-by-chat-id chat-id])]) - (fn [[invitations]] - (filter #(= constants/invitation-state-requested (:state %)) invitations))) - (re-frame/reg-sub :chat/mention-suggestions :<- [:chats/current-chat-id] @@ -352,24 +330,6 @@ (fn [previews] (get previews :unfurled))) -(re-frame/reg-sub - :chats/status-link-previews-unfurled - :<- [:chat/status-link-previews] - (fn [previews] - (:unfurled previews))) - -(re-frame/reg-sub - :chats/link-previews? - :<- [:chats/link-previews-unfurled] - (fn [previews] - (boolean (seq previews)))) - -(re-frame/reg-sub - :chats/status-link-previews? - :<- [:chats/status-link-previews-unfurled] - (fn [status-link-previews] - (boolean (seq status-link-previews)))) - (re-frame/reg-sub :camera-roll/total-photos-count-android (fn [{:keys [camera-roll/albums]}] diff --git a/src/status_im/subs/communities.cljs b/src/status_im/subs/communities.cljs index a7f197b2fd61..09f3d46f9956 100644 --- a/src/status_im/subs/communities.cljs +++ b/src/status_im/subs/communities.cljs @@ -252,20 +252,6 @@ (fn [requests [_ community-id]] (:id (get requests community-id)))) -(re-frame/reg-sub - :communities/has-pending-request-to-join? - (fn [[_ community-id]] - (re-frame/subscribe [:communities/my-pending-request-to-join community-id])) - (fn [request] - (boolean request))) - -(re-frame/reg-sub - :communities/edited-community - :<- [:communities] - :<- [:communities/community-id-input] - (fn [[communities community-id]] - (get communities community-id))) - (re-frame/reg-sub :communities/current-community :<- [:communities] diff --git a/src/status_im/subs/general.cljs b/src/status_im/subs/general.cljs index 50b1b01c52d2..787edd619cd5 100644 --- a/src/status_im/subs/general.cljs +++ b/src/status_im/subs/general.cljs @@ -45,12 +45,6 @@ (when-let [network (get networks current-network)] (assoc network :rpc-network? (get-in network [:config :UpstreamConfig :Enabled]))))) -(re-frame/reg-sub - :chain-keyword - :<- [:current-network] - (fn [network] - (chain/network->chain-keyword network))) - (re-frame/reg-sub :chain-name :<- [:current-network] @@ -63,12 +57,6 @@ (fn [network] (chain/network->chain-id network))) -(re-frame/reg-sub - :mainnet? - :<- [:chain-id] - (fn [chain-id] - (= 1 chain-id))) - (re-frame/reg-sub :network-name :<- [:current-network] @@ -98,12 +86,6 @@ (fn [[params view-id-db] [_ view-id]] (get params (or view-id view-id-db)))) -(re-frame/reg-sub - :wallet-legacy/search-recipient-filter - :<- [:ui/search] - (fn [search] - (get search :recipient-filter))) - (defn- node-version [web3-node-version] (or web3-node-version "N/A")) diff --git a/src/status_im/subs/profile.cljs b/src/status_im/subs/profile.cljs index abf449aecd07..81fac798f0ec 100644 --- a/src/status_im/subs/profile.cljs +++ b/src/status_im/subs/profile.cljs @@ -100,18 +100,6 @@ (fn [{:keys [public-key]}] public-key)) -(re-frame/reg-sub - :profile/webview-debug - :<- [:profile/profile] - (fn [{:keys [webview-debug]}] - webview-debug)) - -(re-frame/reg-sub - :profile/light-client-enabled? - :<- [:profile/profile] - (fn [profile] - (get-in profile [:wakuv2-config :LightClient]))) - (re-frame/reg-sub :profile/store-confirmations-enabled? :<- [:profile/profile] @@ -130,18 +118,6 @@ (fn [profile] (:test-networks-enabled? profile))) -(re-frame/reg-sub - :profile/universal-profile-url - :<- [:profile/profile] - (fn [profile] - (:universal-profile-url profile))) - -(re-frame/reg-sub - :profile/peer-syncing-enabled? - :<- [:profile/profile] - (fn [profile] - (:peer-syncing-enabled? profile))) - (re-frame/reg-sub :profile/compressed-key :<- [:profile/profile] @@ -154,18 +130,6 @@ (fn [current-account] (select-keys current-account [:name :preferred-name :public-key :image :images]))) -(re-frame/reg-sub - :multiaccount/preferred-name - :<- [:profile/profile] - (fn [{:keys [preferred-name]}] - preferred-name)) - -(re-frame/reg-sub - :multiaccount/default-account - :<- [:wallet/accounts] - (fn [accounts] - (first accounts))) - (re-frame/reg-sub :sign-in-enabled? :<- [:profile/login] @@ -204,22 +168,6 @@ (fn [[accounts address]] (some #(when (= (:address %) address) %) accounts))) -(re-frame/reg-sub - :account-by-address - :<- [:profile/wallet-accounts] - (fn [accounts [_ address]] - (when (string? address) - (some #(when (= (string/lower-case (:address %)) - (string/lower-case address)) - %) - accounts)))) - -(re-frame/reg-sub - :accounts-without-watch-only - :<- [:profile/wallet-accounts] - (fn [accounts] - (filter #(not= (:type %) :watch) accounts))) - (re-frame/reg-sub :visible-accounts-without-watch-only :<- [:profile/wallet-accounts] @@ -270,11 +218,6 @@ (fn [{:keys [preview-privacy?]}] (boolean preview-privacy?))) -(re-frame/reg-sub :profile/installation-id - :<- [:profile/profile] - (fn [{:keys [installation-id]}] - installation-id)) - (defn- replace-multiaccount-image-uri [profile ens-names port font-file avatar-opts theme] (let [{:keys [key-uid ens-name? images @@ -343,35 +286,9 @@ (fn [[{:keys [key-uid]} profiles]] (get profiles key-uid))) -(re-frame/reg-sub - :profile/login-processing - :<- [:profile/login] - (fn [{:keys [processing]}] - processing)) - (re-frame/reg-sub :profile/recovery-phrase-backed-up? :<- [:profile/profile] (fn [profile] (not (boolean (seq (:mnemonic profile)))))) -;; LINK PREVIEW -;; ======================================================================================================== - -(re-frame/reg-sub - :link-preview/cache - :<- [:profile/profile] - (fn [multiaccount [_ link]] - (get-in multiaccount [:link-previews-cache link]))) - -(re-frame/reg-sub - :link-preview/enabled-sites - :<- [:profile/profile] - (fn [multiaccount] - (get multiaccount :link-previews-enabled-sites))) - -(re-frame/reg-sub - :link-preview/link-preview-request-enabled - :<- [:profile/profile] - (fn [multiaccount] - (get multiaccount :link-preview-request-enabled))) diff --git a/src/status_im/subs/wallet/buy.cljs b/src/status_im/subs/wallet/buy.cljs index 5adf82ba0037..93b794ced32c 100644 --- a/src/status_im/subs/wallet/buy.cljs +++ b/src/status_im/subs/wallet/buy.cljs @@ -20,13 +20,3 @@ :wallet/wallet-buy-crypto-provider :<- [:wallet/wallet-buy-crypto] :-> :provider) - -(rf/reg-sub - :wallet/wallet-buy-crypto-recurrent? - :<- [:wallet/wallet-buy-crypto] - :-> :recurrent?) - -(rf/reg-sub - :wallet/wallet-buy-crypto-network - :<- [:wallet/wallet-buy-crypto] - :-> :network) diff --git a/src/status_im/subs/wallet/collectibles.cljs b/src/status_im/subs/wallet/collectibles.cljs index dcc667011536..11178d09c916 100644 --- a/src/status_im/subs/wallet/collectibles.cljs +++ b/src/status_im/subs/wallet/collectibles.cljs @@ -116,15 +116,6 @@ (fn [collectible] (:gradient-color collectible :gradient-1))) -(re-frame/reg-sub - :wallet/collectible-details-owner - :<- [:wallet/accounts] - (fn [accounts [_ collectible]] - (let [owner-address (-> collectible :ownership first :address)] - (some #(when (= (:address %) owner-address) - %) - accounts)))) - (re-frame/reg-sub :wallet/total-owned-collectible :<- [:wallet/accounts-without-watched-accounts] diff --git a/src/status_im/subs/wallet/collectibles_test.cljs b/src/status_im/subs/wallet/collectibles_test.cljs deleted file mode 100644 index 5654414d4e7f..000000000000 --- a/src/status_im/subs/wallet/collectibles_test.cljs +++ /dev/null @@ -1,26 +0,0 @@ -(ns status-im.subs.wallet.collectibles-test - (:require - [cljs.test :refer [is testing]] - [re-frame.db :as rf-db] - [status-im.subs.root] - [status-im.subs.wallet.collectibles] - [test-helpers.unit :as h] - [utils.re-frame :as rf])) - -(def collectible-owner-wallet - {:ui {:collectible {:details {:ownership [{:address "0x1"}]}}} - :accounts {"0x1" {:address "0x1" - :name "account 1" - :color "army"}}}) - -(h/deftest-sub :wallet/collectible-details-owner - [sub-name] - (testing "correct owner of the last collectible should be returned" - (swap! rf-db/app-db assoc :wallet collectible-owner-wallet) - (let [collectible (-> collectible-owner-wallet :ui :collectible :details) - result (rf/sub [sub-name collectible])] - (is (= {:name "account 1" - :color "army" - :address "0x1" - :network-preferences-names #{}} - result))))) diff --git a/src/status_im/subs/wallet/dapps/proposals_test.cljs b/src/status_im/subs/wallet/dapps/proposals_test.cljs index 374cfcf6ff42..51c9301e2c52 100644 --- a/src/status_im/subs/wallet/dapps/proposals_test.cljs +++ b/src/status_im/subs/wallet/dapps/proposals_test.cljs @@ -42,41 +42,6 @@ :origin "https://lab.web3modal.com" :isScam false}}}}) -(def sample-session-empty-name - {:session-proposal - {:id 1716798889093634 - :params - {:id 1716798889093634 - :pairingTopic "9b18e1348817a548bbc97f9b4a09278f4fdf7c984e4a61ddf461bd1f57710d33" - :expiryTimestamp 1716799189 - :requiredNamespaces {} - :optionalNamespaces {:eip155 - {:chains ["eip155:1" "eip155:42161" "eip155:137" "eip155:43114" "eip155:56" - "eip155:10" "eip155:100" - "eip155:324" "eip155:7777777" "eip155:8453" "eip155:42220" - "eip155:1313161554" "eip155:11155111" "eip155:11155420"] - :methods ["personal_sign" "eth_accounts" "eth_requestAccounts" - "eth_sendRawTransaction" "eth_sendTransaction" - "eth_sign" "eth_signTransaction" "eth_signTypedData" - "eth_signTypedData_v3" "eth_signTypedData_v4" - "wallet_addEthereumChain" "wallet_getCallsStatus" - "wallet_getCapabilities" "wallet_getPermissions" - "wallet_registerOnboarding" "wallet_requestPermissions" - "wallet_scanQRCode" "wallet_sendCalls" - "wallet_showCallsStatus" "wallet_switchEthereumChain" - "wallet_watchAsset"] - :events ["chainChanged" "accountsChanged"]}} - :relays [{:protocol "irn"}] - :proposer {:publicKey "cddea055b8974d93380e6c7e72110145506c06524047866f8034f3db0990137a" - :metadata {:name "" - :description "Web3Modal Laboratory" - :url "https://lab.web3modal.com" - :icons ["https://avatars.githubusercontent.com/u/37784886"]}}} - :verifyContext {:verified {:verifyUrl "https://verify.walletconnect.com" - :validation "VALID" - :origin "https://lab.web3modal.com" - :isScam false}}}}) - (h/deftest-sub :wallet-connect/session-proposer [sub-name] (testing "Return the session proposer public key and metadata" diff --git a/src/status_im/subs/wallet/send.cljs b/src/status_im/subs/wallet/send.cljs index 9ca943136d49..69abd6ab281f 100644 --- a/src/status_im/subs/wallet/send.cljs +++ b/src/status_im/subs/wallet/send.cljs @@ -29,11 +29,6 @@ :<- [:wallet/wallet-send] :-> :route) -(rf/reg-sub - :wallet/send-token - :<- [:wallet/wallet-send] - :-> :token) - (rf/reg-sub :wallet/send-token-symbol :<- [:wallet/wallet-send] @@ -44,11 +39,6 @@ :<- [:wallet/wallet-send] :-> :transaction-ids) -(rf/reg-sub - :wallet/just-completed-transaction - :<- [:wallet/wallet-send] - :-> :just-completed-transaction?) - (rf/reg-sub :wallet/send-amount :<- [:wallet/wallet-send] @@ -91,11 +81,6 @@ recipient))) (distinct))))) -(rf/reg-sub - :wallet/send-token-not-supported-in-receiver-networks? - :<- [:wallet/wallet-send] - :-> :token-not-supported-in-receiver-networks?) - (rf/reg-sub :wallet/bridge-from-networks :<- [:wallet/wallet-send] diff --git a/src/status_im/subs/wallet/wallet.cljs b/src/status_im/subs/wallet/wallet.cljs index e92c1193941c..2bed7513cef9 100644 --- a/src/status_im/subs/wallet/wallet.cljs +++ b/src/status_im/subs/wallet/wallet.cljs @@ -627,23 +627,6 @@ (group-by :address $) (update-vals $ #(filter positive-balance-in-any-chain? (:tokens (first %)))))))) -(rf/reg-sub - :wallet/accounts-with-current-asset - :<- [:wallet/operable-accounts] - :<- [:wallet/operable-addresses-tokens-with-positive-balance] - :<- [:wallet/wallet-send-token-symbol] - :<- [:wallet/wallet-send-token] - (fn [[accounts addresses-tokens token-symbol token]] - (if-let [asset-symbol (or token-symbol (:symbol token))] - (let [addresses-with-asset (as-> addresses-tokens $ - (update-vals $ #(set (map :symbol %))) - (keep (fn [[address token-symbols]] - (when (token-symbols asset-symbol) address)) - $) - (set $))] - (filter #(addresses-with-asset (:address %)) accounts)) - accounts))) - (rf/reg-sub :wallet/operable-addresses-with-token-symbol :<- [:wallet/operable-addresses-tokens-with-positive-balance] diff --git a/src/status_im/subs/wallet/wallet_test.cljs b/src/status_im/subs/wallet/wallet_test.cljs index ca751782e2d7..f9c34d757729 100644 --- a/src/status_im/subs/wallet/wallet_test.cljs +++ b/src/status_im/subs/wallet/wallet_test.cljs @@ -500,58 +500,6 @@ :tokens tokens-0x2}) (rf/sub [sub-name]))))) -(h/deftest-sub :wallet/accounts-with-current-asset - [sub-name] - (testing "returns the accounts list with the current asset using token-symbol" - (swap! rf-db/app-db - #(-> % - (assoc-in [:wallet :accounts] accounts-with-tokens) - (assoc-in [:wallet :ui :send :token-symbol] "ETH"))) - (let [result (rf/sub [sub-name])] - (is (match? result - [{:tokens [{:symbol "ETH" - :balances-per-chain {1 {:raw-balance "100"}}} - {:symbol "SNT" - :balances-per-chain {1 {:raw-balance "100"}}}] - :network-preferences-names #{} - :customization-color nil - :operable? true - :operable :fully - :address "0x1"}])))) - - (testing "returns the accounts list with the current asset using token" - (swap! rf-db/app-db - #(-> % - (assoc-in [:wallet :accounts] accounts-with-tokens) - (assoc-in [:wallet :ui :send :token] {:symbol "ETH"}))) - (let [result (rf/sub [sub-name])] - (is (match? result - [{:tokens [{:symbol "ETH" - :balances-per-chain {1 {:raw-balance "100"}}} - {:symbol "SNT" - :balances-per-chain {1 {:raw-balance "100"}}}] - :network-preferences-names #{} - :customization-color nil - :operable? true - :operable :fully - :address "0x1"}])))) - - (testing - "returns the full accounts list with the current asset using token-symbol if each account has the asset" - (swap! rf-db/app-db - #(-> % - (assoc-in [:wallet :accounts] accounts-with-tokens) - (assoc-in [:wallet :ui :send :token-symbol] "SNT"))) - (let [result (rf/sub [sub-name])] - (is (match? result (vals accounts-with-tokens))))) - - (testing "returns the accounts list when there is no current asset" - (swap! rf-db/app-db - #(-> % - (assoc-in [:wallet :accounts] accounts-with-tokens))) - (let [result (rf/sub [sub-name])] - (is (match? result (vals accounts-with-tokens)))))) - (h/deftest-sub :wallet/network-preference-details [sub-name] (testing "returns current viewing account address" diff --git a/src/test_helpers/component.cljs b/src/test_helpers/component.cljs index 050f37b52dcf..7abe97c70082 100644 --- a/src/test_helpers/component.cljs +++ b/src/test_helpers/component.cljs @@ -58,19 +58,6 @@ ([component theme] (rtl/render (reagent/as-element [quo.theme/provider theme component])))) -(def unmount - "Unmount rendered component. - Sometimes useful to be called in a REPL, but unnecessary when rendering - components with Jest, since components are automatically unmounted after each - test." - (with-node-or-screen :unmount)) - -(def debug - "Pretty-print to STDOUT the current component tree." - (with-node-or-screen :debug)) - -(def within rtl/within) - (defn wait-for ([condition] (wait-for condition {})) ([condition options] @@ -93,11 +80,8 @@ ;; For this reason, find-* functions only work within the Jest runtime, hence ;; using the wrapper function `with-node-or-screen` is unnecessary. -(def find-by-text (comp rtl/screen.findByText name)) - ;;; Queries that work with a REPL and with Jest -(def get-all-by-text (with-node-or-screen :get-all-by-text)) (def get-by-text (with-node-or-screen :get-by-text)) (def query-all-by-text (with-node-or-screen :query-all-by-text)) (def query-by-text (with-node-or-screen :query-by-text)) @@ -108,37 +92,7 @@ (def query-all-by-label-text (with-node-or-screen :query-all-by-label-text)) (def query-by-label-text (with-node-or-screen :query-by-label-text)) -(def get-all-by-display-value (with-node-or-screen :get-all-by-display-value)) -(def get-by-display-value (with-node-or-screen :get-by-display-value)) -(def query-all-by-display-value (with-node-or-screen :query-all-by-display-value)) -(def query-by-display-value (with-node-or-screen :query-by-display-value)) - -(def get-all-by-placeholder-text (with-node-or-screen :get-all-by-placeholder-text)) -(def get-by-placeholder-text (with-node-or-screen :get-by-placeholder-text)) -(def query-all-by-placeholder-text (with-node-or-screen :query-all-by-placeholder-text)) -(def query-by-placeholder-text (with-node-or-screen :query-by-placeholder-text)) - -(def get-all-by-role (with-node-or-screen :get-all-by-role)) -(def get-by-role (with-node-or-screen :get-by-role)) -(def query-all-by-role (with-node-or-screen :query-all-by-role)) -(def query-by-role (with-node-or-screen :query-by-role)) - -(def get-all-by-test-id (with-node-or-screen :get-all-by-test-id)) (def get-by-test-id (with-node-or-screen :get-by-test-id)) -(def query-all-by-test-id (with-node-or-screen :query-all-by-test-id)) -(def query-by-test-id (with-node-or-screen :query-by-test-id)) - -(defn get-all-by-translation-text - ([translation] - (get-all-by-translation-text rtl/screen translation nil)) - ([translation translation-opts] - (get-all-by-translation-text rtl/screen translation translation-opts)) - ([^js node translation translation-opts & args] - (apply (with-node-or-screen :get-all-by-text) - node - (i18n/label translation translation-opts) - args))) - (defn get-by-translation-text ([translation] (get-by-translation-text rtl/screen translation nil)) @@ -161,17 +115,6 @@ (i18n/label translation translation-opts) args))) -(defn query-all-by-translation-text - ([translation] - (query-all-by-translation-text rtl/screen translation nil)) - ([translation translation-opts] - (query-all-by-translation-text rtl/screen translation translation-opts)) - ([^js node translation translation-opts & args] - (apply (with-node-or-screen :query-all-by-text) - node - (i18n/label translation translation-opts) - args))) - ;;; Jest utilities (def ^:private jest? diff --git a/src/test_helpers/integration.cljs b/src/test_helpers/integration.cljs index 646db61716b0..9aad647e0e46 100644 --- a/src/test_helpers/integration.cljs +++ b/src/test_helpers/integration.cljs @@ -6,7 +6,6 @@ [native-module.core :as native-module] [promesa.core :as promesa] [re-frame.core :as rf] - [re-frame.interop :as rf.interop] status-im.events status-im.navigation.core status-im.subs.root @@ -43,10 +42,6 @@ sleepy." (* 60 1000)) -(defn initialize-app! - [] - (rf/dispatch [:app-started])) - (defn create-multiaccount! [] (rf/dispatch [:profile.create/create-and-login @@ -77,21 +72,6 @@ [] (is (wallet-loaded?))) -(defn assert-community-created - [] - (is (= @(rf/subscribe [:communities/create]) constants/community))) - -(defn create-new-account! - [] - (rf/dispatch-sync [:wallet-legacy.accounts/start-adding-new-account {:type :generate}]) - (rf/dispatch-sync [:set-in [:add-account :account :name] constants/account-name]) - (rf/dispatch [:wallet-legacy.accounts/add-new-account (native-module/sha3 constants/password)])) - -(defn assert-new-account-created - [] - (is (true? (some #(= (:name %) constants/account-name) - @(rf/subscribe [:profile/wallet-accounts]))))) - (defn logout [] (log/info (str "==== before dispatch logout ====")) @@ -291,23 +271,4 @@ (done))))}) ([] (fixture-session [:new-account]))) -(defn fixture-silence-reframe - "Fixture to disable most re-frame messages. - Avoid using this fixture for non-dev purposes because in the CI output it's - desirable to have more data to debug, not less. - - Example messages disabled: - - - Warning about subscriptions being used in non-reactive contexts. - - Debug message \"Handling re-frame event: XYZ\". - - Usage: - - (use-fixtures :once (h/fixture-silence-re-frame)) - " - [] - {:before (fn [] - (set! rf.interop/debug-enabled? false)) - :after (fn [] - (set! rf.interop/debug-enabled? true))}) diff --git a/src/test_helpers/matchers.cljs b/src/test_helpers/matchers.cljs index 313424a0e6f3..f294052f816d 100644 --- a/src/test_helpers/matchers.cljs +++ b/src/test_helpers/matchers.cljs @@ -9,6 +9,8 @@ (defrecord Mismatch [summary match-result]) +;; used in matchers.clj +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn tagged-for-pretty-printing [actual-summary result] (->Mismatch actual-summary result)) @@ -18,6 +20,8 @@ (-pr-writer [this writer _] (-write writer (printer/as-string (-> this :match-result ::result/value))))) +;; used in matchers.clj +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn with-file+line-info [report] (merge (t/file-and-line (js/Error.) 4) diff --git a/src/test_helpers/unit.clj b/src/test_helpers/unit.clj index 60472f78a801..2fe0438c5fec 100644 --- a/src/test_helpers/unit.clj +++ b/src/test_helpers/unit.clj @@ -2,7 +2,7 @@ (:require [clojure.spec.alpha :as s] [clojure.string :as string] - [clojure.walk :as walk])) + [clojure.walk])) (defn- keyword->test-name [sub-name] diff --git a/src/test_helpers/unit.cljs b/src/test_helpers/unit.cljs index c6081afe1786..b8e27228c672 100644 --- a/src/test_helpers/unit.cljs +++ b/src/test_helpers/unit.cljs @@ -9,92 +9,15 @@ ;; We must require test-helpers.matchers namespace to register the custom cljs.test directive ;; `match-strict?` (:require - [re-frame.core :as rf] [re-frame.db :as rf-db] - [re-frame.events :as rf-events] - [re-frame.registrar :as rf-registrar] [re-frame.subs :as rf-subs] [taoensso.timbre :as log] test-helpers.matchers)) ;; We must require `test-helpers.matchers` this namespace to register the custom cljs.test ;; directive `match-strict?`. -(defn db - "A simple wrapper to get the latest value from the app db." - [] - @rf-db/app-db) - -(defn register-helper-events - "Register utility events for testing. - - Note that re-frame-test removes such events if they're declared in the scope - of the macro `day8.re-frame.test/run-test-sync` (or the async variant)." - [] - (rf/reg-event-db - :test/assoc-in - (fn [app-db [_ path value]] - (assoc-in app-db path value)))) - -(defn spy-event-fx - "Re-register event effect using id `id`, but conj to `state` the event - arguments before calling the original handler. - - Callers of this function can later on deref `state` to make assertions. - - It's recommended to run this function in the scope of the macro - `day8.re-frame.test/run-test-sync` (or the async variant) as they - automatically clean up effects." - [state id] - (let [interceptors (get-in @rf-registrar/kind->id->handler [:event id])] - (rf-events/register - id - (concat (butlast interceptors) - (list {:id :test/spy-event-fx - :before (fn [context] - (swap! state conj {:id id :args (get-in context [:coeffects :event])}) - context)} - (last interceptors)))))) - -(defn spy-fx - "Re-register effect using id `id`, but conj to `state` the effect arguments - before calling the original effect handler. - - Callers of this function can later on inspect `state` to make assertions. - - It's recommended to run this function in the scope of the macro - `day8.re-frame.test/run-test-sync` (or the async variant) as they - automatically clean up effects." - [state id] - (let [original-fn (get-in @rf-registrar/kind->id->handler [:fx id])] - (rf/reg-fx - id - (fn [fx-args] - (swap! state conj {:id id :args fx-args}) - (original-fn fx-args))))) - -(defn stub-fx-with-callbacks - "Re-register effect using id `id` with a no-op version. - - This function is useful to redefine effects that expect callbacks, usually to - pass downstream dummy data to successful/failure events. In re-frame parlance, - such effects accept on-success and on-error keywords. - - The original effect handler for `id` is expected to receive a single map as - argument with either :on-success or :on-error keywords. - - This function expects to receive either `on-success` or `on-error`, but not - both. If both are passed, `on-error` will be preferred." - [id & {:keys [on-success on-error]}] - (rf/reg-fx - id - (fn [[fx-map]] - (let [original-on-error (:on-error fx-map) - original-on-success (:on-success fx-map)] - (cond (and original-on-error on-error) - (original-on-error (on-error fx-map)) - (and original-on-success on-success) - (original-on-success (on-success fx-map))))))) +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} ;; used in unit.clj (defn restore-app-db "Saves current app DB, calls `f` and restores the original app DB. diff --git a/src/tests/contract_test/wallet_test.cljs b/src/tests/contract_test/wallet_test.cljs index 73efc1b40199..4ccd756c1eac 100644 --- a/src/tests/contract_test/wallet_test.cljs +++ b/src/tests/contract_test/wallet_test.cljs @@ -107,26 +107,3 @@ chain-id ens-address)] (assert-address-details response))))) - -(defn assert-search-ens - [expected-result actual-result] - (is (= expected-result actual-result))) - -#_(deftest wallet-search-ens-test - (h/test-async :wallet/search-ens - (fn [] - (promesa/let [_ (h/enable-testnet!)] - (let [test-cases [{:description "Test on Ethereum mainnet" - :ens-name "test.eth" - :chain-id constants/ethereum-mainnet-chain-id - :expected-result "0xeefb13c7d42efcc655e528da6d6f7bbcf9a2251d"} - {:description "Test on Sepolia testnet" - :ens-name "code.eth" - :chain-id constants/ethereum-sepolia-chain-id - :expected-result "0x035ebd096afa6b98372494c7f08f3402324117d3"}]] - (promesa/all - (map (fn [{:keys [ens-name chain-id expected-result]}] - (promesa/let [ens-address - (rpc-events/call-async "ens_addressOf" false chain-id ens-name)] - (assert-search-ens expected-result ens-address))) - test-cases))))))) diff --git a/src/tests/integration_test/constants.cljs b/src/tests/integration_test/constants.cljs index 822e0b5980e5..7142f8760c42 100644 --- a/src/tests/integration_test/constants.cljs +++ b/src/tests/integration_test/constants.cljs @@ -2,8 +2,6 @@ (def password "testabc") -(def community {:membership 1 :name "foo" :description "bar"}) - (def account-name "account-abc") (def derivation-path "m/43'/60'/1581'/0'/0") diff --git a/src/utils/address.cljs b/src/utils/address.cljs index 14d7a0957c02..b1ddc381aca2 100644 --- a/src/utils/address.cljs +++ b/src/utils/address.cljs @@ -2,7 +2,6 @@ (:require [clojure.string :as string] [native-module.core :as native-module] - [utils.ethereum.eip.eip55 :as eip55] [utils.ethereum.eip.eip681 :as eip681])) @@ -20,11 +19,6 @@ hex (str hex-prefix hex)))) -(defn naked-address - [s] - (when s - (string/replace s hex-prefix ""))) - (defn address? [address] (native-module/address? address)) @@ -43,11 +37,6 @@ (when value (str (subs value 0 6) "\u2026" (subs value (- (count value) 3) (count value))))) -(defn get-shortened-checksum-address - [address] - (when address - (get-shortened-key (eip55/address->checksum (normalized-hex address))))) - (defn get-abbreviated-profile-url "The goal here is to generate a string that begins with status.app/u/ joined with the 1st 5 characters of the encoded data followed by an ellipsis diff --git a/src/utils/collection.cljs b/src/utils/collection.cljs index d7c34186a5b3..4e556d0d2510 100644 --- a/src/utils/collection.cljs +++ b/src/utils/collection.cljs @@ -20,8 +20,3 @@ [k coll] (let [groups (group-by k coll)] (map #(first (groups %)) (distinct (map k coll))))) - -(defn map-keys - [f m] - (->> (map (fn [[k v]] [(f k) v]) m) - (into {}))) diff --git a/src/utils/collection_test.cljs b/src/utils/collection_test.cljs new file mode 100644 index 000000000000..8d7c60b6a415 --- /dev/null +++ b/src/utils/collection_test.cljs @@ -0,0 +1,12 @@ +(ns utils.collection-test + (:require + [cljs.test :refer-macros [deftest is]] + [utils.collection :as c])) + +(deftest first-index-test + (is (= 2 + (c/first-index (partial = :test) + '(:a :b :test :c :test)))) + (is (= nil + (c/first-index (partial = :test) + '(:a :b :c))))) diff --git a/src/utils/datetime.cljs b/src/utils/datetime.cljs index ffca333637a7..e82976d270ee 100644 --- a/src/utils/datetime.cljs +++ b/src/utils/datetime.cljs @@ -82,7 +82,6 @@ "h:mm:ss a")) ;;;; Date formats -(defn- short-date-format [_] "dd MMM") (defn- short-date-format-with-time [_] "dd MMM h:mm a") (defn- datetime-within-one-week-format @@ -118,7 +117,6 @@ (def date-time-fmt (get-formatter-fn medium-date-time-format)) (def date-fmt (get-formatter-fn medium-date-format)) (def time-fmt (get-formatter-fn short-time-format)) -(def short-date-fmt (get-formatter-fn short-date-format)) (def short-date-with-time-fmt (get-formatter-fn short-date-format-with-time)) (def datetime-within-one-week-fmt (get-formatter-fn datetime-within-one-week-format)) @@ -223,13 +221,6 @@ timestamp->relative full-date->short-date)) -(defn timestamp->mini-date - [ms] - (.format ^js (short-date-fmt) - (-> ms - t.coerce/from-long - (t/plus time-zone-offset)))) - (defn timestamp->time [ms] (.format ^js (time-fmt) @@ -237,13 +228,6 @@ t.coerce/from-long (t/plus time-zone-offset)))) -(defn timestamp->date-key - [ms] - (keyword (t.format/unparse (t.format/formatter "YYYYMMDD") - (-> ms - t.coerce/from-long - (t/plus time-zone-offset))))) - (defn timestamp->long-date [ms] (.format ^js (date-time-fmt) @@ -251,15 +235,6 @@ t.coerce/from-long (t/plus time-zone-offset)))) -(defn format-time-ago - [diff unit] - (let [name (i18n/label-pluralize diff (:name unit))] - (if (= :t/datetime-second-short (:name unit)) - (i18n/label :t/now) - (i18n/label :t/datetime-ago-format-short - {:ago (i18n/label :t/datetime-ago) - :number diff - :time-intervals name})))) (defn seconds-ago [date-time] (let [time-now (t/now)] @@ -267,17 +242,6 @@ (t/in-seconds (t/interval date-time time-now)) 0))) -(defn time-ago - [date-time] - (let [diff (seconds-ago date-time) - unit (first (drop-while #(and (>= diff (:limit %)) - (:limit %)) - default-units))] - (-> (/ diff (:in-second unit)) - Math/floor - int - (format-time-ago unit)))) - (defn time-ago-long ([date-time units] (let [time-ago-seconds (seconds-ago date-time) diff --git a/src/utils/datetime_test.cljs b/src/utils/datetime_test.cljs index 07f0b99bd5a0..78021bf10328 100644 --- a/src/utils/datetime_test.cljs +++ b/src/utils/datetime_test.cljs @@ -24,8 +24,6 @@ (def epoch 0) ;; 1970-01-03 00:00:00 UTC (def epoch-plus-3d 172800000) -(def mock-current-time-epoch 1655731506000) - (deftest is-24-hour-locale-en-test (is (false? (#'utils.datetime/is-24-hour-locsym (i18n-goog/locale-symbols "en"))))) diff --git a/src/utils/ens/core.cljs b/src/utils/ens/core.cljs index 9e8a12a51fa8..a97d2889fe2e 100644 --- a/src/utils/ens/core.cljs +++ b/src/utils/ens/core.cljs @@ -9,15 +9,6 @@ (def default-address "0x0000000000000000000000000000000000000000") (def default-key "0x0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") -(def default-hash "0x0000000000000000000000000000000000000000000000000000000000000000") - -(defn valid-eth-name-prefix? - [prefix] - (not - (or (string/blank? prefix) - (string/ends-with? prefix ".") - (string/includes? prefix "..")))) - (defn is-valid-eth-name? [ens-name] (and ens-name diff --git a/src/utils/ethereum/chain.cljs b/src/utils/ethereum/chain.cljs index ae3bdc8de2b2..05eafb0c604c 100644 --- a/src/utils/ethereum/chain.cljs +++ b/src/utils/ethereum/chain.cljs @@ -20,27 +20,10 @@ (or (some #(when (= i (:id (val %))) (key %)) chains) :custom)) -(defn chain-id->chain-name - [i] - (or (some #(when (= i (:id (val %))) (:name (val %))) chains) - :custom)) - (defn chain-keyword->chain-id [k] (get-in chains [k :id])) -(defn chain-keyword->snt-symbol - [k] - (case k - :mainnet :SNT - :STT)) - -(defn testnet? - [id] - (contains? #{(chain-keyword->chain-id :sepolia) - (chain-keyword->chain-id :bsc-testnet)} - id)) - (defn network->chain-id [network] (get-in network [:config :NetworkId])) diff --git a/src/utils/ethereum/eip/eip681_test.cljs b/src/utils/ethereum/eip/eip681_test.cljs index 832247c3f7ea..6b53a00b0110 100644 --- a/src/utils/ethereum/eip/eip681_test.cljs +++ b/src/utils/ethereum/eip/eip681_test.cljs @@ -105,19 +105,6 @@ :function-name "transfer" :function-arguments {:address "gimme.eth" :uint256 "1"}}))) -(def all-tokens - {:mainnet {"0x744d70fdbe2ba4cf95131626614a1763df805b9e" {:address - "0x744d70fdbe2ba4cf95131626614a1763df805b9e" - :name "Status Network Token" - :symbol :SNT - :decimals 18}} - :sepolia {"0xE452027cdEF746c7Cd3DB31CB700428b16cD8E51" - {:address - "0xE452027cdEF746c7Cd3DB31CB700428b16cD8E51" - :name "Status Test Token" - :symbol :STT - :decimals 18}}}) - (deftest generate-uri-test (is (= nil (eip681/generate-uri nil nil))) (is (= "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" diff --git a/src/utils/i18n.cljs b/src/utils/i18n.cljs index 479e59bb85cb..f2e11643392b 100644 --- a/src/utils/i18n.cljs +++ b/src/utils/i18n.cljs @@ -1,8 +1,7 @@ (ns utils.i18n (:require ["i18n-js" :as i18n] - [clojure.string :as string] - [utils.i18n-goog :as i18n-goog])) + [clojure.string :as string])) (defn setup [default-device-language translations-by-locale] @@ -69,5 +68,3 @@ (def locale (.-locale i18n)) - -(def format-currency i18n-goog/format-currency) diff --git a/src/utils/i18n_goog.cljs b/src/utils/i18n_goog.cljs index 57014dae8e8b..0df05a8025a5 100644 --- a/src/utils/i18n_goog.cljs +++ b/src/utils/i18n_goog.cljs @@ -366,79 +366,3 @@ [locale format-fn] (let [locsym (locale-symbols locale)] (goog.i18n.DateTimeFormat. (format-fn locsym) locsym))) - -(defn format-currency - "Formats an amount of a currency based on the currency pattern - If currency-symbol? is false, the currency symbol is excluded from the - formatting" - [value currency-code] - (.addTier2Support ^js goog.i18n.currency) - (let [currency-code-to-nfs-map {"ZAR" ^js goog.i18n.NumberFormatSymbols_af - "ETB" ^js goog.i18n.NumberFormatSymbols_am - "EGP" ^js goog.i18n.NumberFormatSymbols_ar - "DZD" ^js goog.i18n.NumberFormatSymbols_ar_DZ - "AZN" ^js goog.i18n.NumberFormatSymbols_az - "BYN" ^js goog.i18n.NumberFormatSymbols_be - "BGN" ^js goog.i18n.NumberFormatSymbols_bg - "BDT" ^js goog.i18n.NumberFormatSymbols_bn - "EUR" ^js goog.i18n.NumberFormatSymbols_br - "BAM" ^js goog.i18n.NumberFormatSymbols_bs - "USD" ^js goog.i18n.NumberFormatSymbols_en - "CZK" ^js goog.i18n.NumberFormatSymbols_cs - "GBP" ^js goog.i18n.NumberFormatSymbols_cy - "DKK" ^js goog.i18n.NumberFormatSymbols_da - "CHF" ^js goog.i18n.NumberFormatSymbols_de_CH - "AUD" ^js goog.i18n.NumberFormatSymbols_en_AU - "CAD" ^js goog.i18n.NumberFormatSymbols_en_CA - "INR" ^js goog.i18n.NumberFormatSymbols_en_IN - "SGD" ^js goog.i18n.NumberFormatSymbols_en_SG - "MXN" ^js goog.i18n.NumberFormatSymbols_es_419 - "IRR" ^js goog.i18n.NumberFormatSymbols_fa - "PHP" ^js goog.i18n.NumberFormatSymbols_fil - "ILS" ^js goog.i18n.NumberFormatSymbols_he - "HRK" ^js goog.i18n.NumberFormatSymbols_hr - "HUF" ^js goog.i18n.NumberFormatSymbols_hu - "AMD" ^js goog.i18n.NumberFormatSymbols_hy - "IDR" ^js goog.i18n.NumberFormatSymbols_id - "ISK" ^js goog.i18n.NumberFormatSymbols_is - "JPY" ^js goog.i18n.NumberFormatSymbols_ja - "GEL" ^js goog.i18n.NumberFormatSymbols_ka - "KZT" ^js goog.i18n.NumberFormatSymbols_kk - "KHR" ^js goog.i18n.NumberFormatSymbols_km - "KRW" ^js goog.i18n.NumberFormatSymbols_ko - "KGS" ^js goog.i18n.NumberFormatSymbols_ky - "CDF" ^js goog.i18n.NumberFormatSymbols_ln - "LAK" ^js goog.i18n.NumberFormatSymbols_lo - "MKD" ^js goog.i18n.NumberFormatSymbols_mk - "MNT" ^js goog.i18n.NumberFormatSymbols_mn - "MDL" ^js goog.i18n.NumberFormatSymbols_mo - "MYR" ^js goog.i18n.NumberFormatSymbols_ms - "MMK" ^js goog.i18n.NumberFormatSymbols_my - "NOK" ^js goog.i18n.NumberFormatSymbols_nb - "NPR" ^js goog.i18n.NumberFormatSymbols_ne - "PLN" ^js goog.i18n.NumberFormatSymbols_pl - "BRL" ^js goog.i18n.NumberFormatSymbols_pt - "RON" ^js goog.i18n.NumberFormatSymbols_ro - "RUB" ^js goog.i18n.NumberFormatSymbols_ru - "RSD" ^js goog.i18n.NumberFormatSymbols_sh - "LKR" ^js goog.i18n.NumberFormatSymbols_si - "ALL" ^js goog.i18n.NumberFormatSymbols_sq - "SEK" ^js goog.i18n.NumberFormatSymbols_sv - "TZS" ^js goog.i18n.NumberFormatSymbols_sw - "THB" ^js goog.i18n.NumberFormatSymbols_th - "TRY" ^js goog.i18n.NumberFormatSymbols_tr - "UAH" ^js goog.i18n.NumberFormatSymbols_uk - "PKR" ^js goog.i18n.NumberFormatSymbols_ur - "UZS" ^js goog.i18n.NumberFormatSymbols_uz - "VND" ^js goog.i18n.NumberFormatSymbols_vi - "CNY" ^js goog.i18n.NumberFormatSymbols_zh - "HKD" ^js goog.i18n.NumberFormatSymbols_zh_HK - "TWD" ^js goog.i18n.NumberFormatSymbols_zh_TW} - nfs (or (get currency-code-to-nfs-map currency-code) - ^js goog.i18n.NumberFormatSymbols_en)] - (.format - ^js - (new ^js goog.i18n.NumberFormat - (let [pattern (.-CURRENCY_PATTERN ^js nfs)] - (string/replace pattern #"\s*¤\s*" ""))) - value))) diff --git a/src/utils/money.cljs b/src/utils/money.cljs index 033ff7d37025..5351ad31b82e 100644 --- a/src/utils/money.cljs +++ b/src/utils/money.cljs @@ -134,11 +134,6 @@ (when bn (.toFixed bn b)))) -(defn to-number - [^js bn] - (when (bignumber? bn) - (.toNumber bn))) - (defn to-string ([^js bn] (to-string bn 10)) @@ -156,11 +151,6 @@ (new BigNumber hex-str 16) (catch :default _ nil))) -(defn wei->str - ([unit n display-unit] - (str (to-fixed (wei-> unit n)) " " display-unit)) - ([unit n] (wei->str unit n (string/upper-case (name unit))))) - (defn wei->ether [n] (wei-> :eth n)) @@ -173,64 +163,12 @@ [n] (->wei :gwei n)) -(defn ether->wei - [^js bn] - (when (bignumber? bn) - (.times bn ^js (bignumber 1e18)))) - (defn token->unit [n decimals] (when-let [^js bn (bignumber n)] (when-let [d (from-decimal decimals)] (.dividedBy bn ^js (bignumber d))))) -(defn unit->token - [n decimals] - (when-let [^js bn (bignumber n)] - (when-let [d (from-decimal decimals)] - (.times bn ^js (bignumber d))))) - -;;NOTE(goranjovic) - We have two basic representations of values that refer to cryptocurrency amounts: -;;formatted and -;; internal. Formatted representation is the one we show on screens and include in reports, whereas -;; internal -;; representation is the one that we pass on to ethereum network for execution, transfer, etc. -;; The difference between the two depends on the number of decimals, i.e. internal representation is -;; expressed in terms -;; of a whole number of smallest divisible parts of the formatted value. -;; -;; E.g. for Ether, it's smallest part is wei or 10^(-18) of 1 ether -;; for arbitrary ERC20 token the smallest part is 10^(-decimals) of 1 token -;; -;; Different tokens can have different number of allowed decimals, so it's necessary to include the -;; decimals parameter -;; to get the amount scale right. - -(defn formatted->internal - [n sym decimals] - (if (= :ETH sym) - (ether->wei n) - (unit->token n decimals))) - -(defn internal->formatted - [n sym decimals] - (if (= :ETH sym) - (wei->ether n) - (token->unit n decimals))) - -(defn fee-value - [gas gas-price] - (.times ^js (bignumber gas) ^js (bignumber gas-price))) - -(defn percent-change - [from to] - (let [^js bnf (bignumber from) - ^js bnt (bignumber to)] - (when (and bnf bnt) - (-> ^js (.dividedBy bnf bnt) - ^js (.minus 1) - ^js (.times 100))))) - (defn with-precision [n decimals] (when-let [^js bn (bignumber n)] @@ -256,15 +194,6 @@ (when (and amount balance) (greater-than-or-equals balance amount))) -(defn fiat-amount-value - [amount-str from to prices] - (-> amount-str - (js/parseFloat) - bignumber - (crypto->fiat (get-in prices [from to] ^js (bignumber 0))) - (with-precision 2) - str)) - (defn- add* [bn1 n2] (.add ^js bn1 n2)) @@ -281,10 +210,6 @@ "Multiply with defaults, this version is able to receive `nil` and takes them as 0." (fnil mul* (bignumber 0) (bignumber 0))) -(defn mul-and-round - [bn1 bn2] - (.round (.mul ^js bn1 bn2) 0)) - (defn- div* [bn1 bn2] (.dividedBy ^js bn1 bn2)) @@ -293,10 +218,6 @@ "Divides with defaults, this version is able to receive `nil` and takes them as 0." (fnil div* (bignumber 0) (bignumber 1))) -(defn div-and-round - [bn1 bn2] - (.round (.dividedBy ^js bn1 bn2) 0)) - (defn fiat->crypto [crypto fiat-price] (when-let [crypto-bn (bignumber crypto)] diff --git a/src/utils/network/core.cljs b/src/utils/network/core.cljs index f8cdaeb17f09..0c85eddee9ba 100644 --- a/src/utils/network/core.cljs +++ b/src/utils/network/core.cljs @@ -40,8 +40,3 @@ vals (map :error) (not-any? identity))) - -(defn chain-id-available? - [current-networks network] - (let [chain-id (get-in network [:config :NetworkId])] - (every? #(not= chain-id (get-in % [1 :config :NetworkId])) current-networks))) diff --git a/src/utils/number.cljs b/src/utils/number.cljs index 1499e74fb6fa..14df6d1daf66 100644 --- a/src/utils/number.cljs +++ b/src/utils/number.cljs @@ -2,7 +2,6 @@ (:require [clojure.string :as string] [native-module.core :as native-module] [utils.hex :as utils.hex] - [utils.money :as utils.money] [utils.money :as money])) (defn naive-round @@ -80,7 +79,7 @@ (defn to-fixed [num decimals] (-> num - (utils.money/to-fixed decimals) + (money/to-fixed decimals) remove-trailing-zeroes)) (defn small-number-threshold diff --git a/src/utils/re_frame.clj b/src/utils/re_frame.clj index 852a22a93290..4d50b634fe55 100644 --- a/src/utils/re_frame.clj +++ b/src/utils/re_frame.clj @@ -29,7 +29,6 @@ - TODO: add suport for `prepost-map?` (don't forget to add it to arglist) - TODO: add validation of macro parameters" {:arglists '([name doc-string? attr-map? [params*] body]) - :deprecated true :superseded-by "utils.re-frame/reg-event-fx"} [name & fdecl] (let [m (if (string? (first fdecl)) diff --git a/src/utils/re_frame_test.cljs b/src/utils/re_frame_test.cljs index 57f1f93a35f7..df9d8fedd0d4 100644 --- a/src/utils/re_frame_test.cljs +++ b/src/utils/re_frame_test.cljs @@ -15,7 +15,7 @@ (rf/defn hello3 {:doc "lol lazy function does nothing"} - [{:keys [db]} b] + [_ _] (identity nil)) (rf/defn hello4 @@ -27,13 +27,13 @@ (rf/defn hello5 "lol lazy function does nothing" {:events [:test]} - [{:keys [db]} b] + [_ _] (identity nil)) (rf/defn hello6 "lol lazy function does nothing" {:events [:test2]} - [{:keys [db]} {:keys [a b]}] + [_ {:keys [a b]}] {:db {:a (identity a) :b b}}) diff --git a/src/utils/string.cljs b/src/utils/string.cljs index d09833b3936d..fc97ceb47959 100644 --- a/src/utils/string.cljs +++ b/src/utils/string.cljs @@ -3,25 +3,6 @@ [clojure.string :as string] [utils.transforms :as transforms])) -(defn truncate-str-memo - "Given string and max threshold, trims the string to threshold length with `...` - appended to end or in the middle if length of the string exceeds max threshold, - returns the same string if threshold is not exceeded" - [s threshold & [middle?]] - (if (and s (< threshold (count s))) - (if middle? - (let [str-len (count s) - max-len (- threshold 3) - start-len (Math/ceil (/ max-len 2)) - end-len (Math/floor (/ max-len 2)) - start (subs s 0 start-len) - end (subs s (- str-len end-len) str-len)] - (str start "..." end)) - (str (subs s 0 (- threshold 3)) "...")) - s)) - -(def truncate-str (memoize truncate-str-memo)) - (defn has-lower-case? [s] (some? (re-find #"[a-z]" s))) diff --git a/src/utils/transforms.cljs b/src/utils/transforms.cljs index 3a08c0092a2e..be9be7e8987e 100644 --- a/src/utils/transforms.cljs +++ b/src/utils/transforms.cljs @@ -53,13 +53,6 @@ [data] (.parse js/JSON data)) -(defn js-dissoc - [js-object & ks] - (let [object-copy (.assign js/Object #js {} js-object)] - (doseq [js-key ks] - (js-delete object-copy (name js-key))) - object-copy)) - (defn json->clj [json] (when-not (= json "undefined") diff --git a/src/utils/worklets/bottom_sheet.cljs b/src/utils/worklets/bottom_sheet.cljs deleted file mode 100644 index fdb8918b9842..000000000000 --- a/src/utils/worklets/bottom_sheet.cljs +++ /dev/null @@ -1,11 +0,0 @@ -(ns utils.worklets.bottom-sheet) - -(def bottom-sheet-js (js/require "../src/js/worklets/bottom_sheet.js")) - -(defn use-translate-y - [window-height bottom-sheet-dy pan-y] - (.useTranslateY ^js bottom-sheet-js window-height bottom-sheet-dy pan-y)) - -(defn use-background-opacity - [translate-y bg-height window-height opacity] - (.useBackgroundOpacity ^js bottom-sheet-js translate-y bg-height window-height opacity)) diff --git a/src/utils/worklets/identifiers_highlighting.cljs b/src/utils/worklets/identifiers_highlighting.cljs deleted file mode 100644 index 76e02fe0c562..000000000000 --- a/src/utils/worklets/identifiers_highlighting.cljs +++ /dev/null @@ -1,31 +0,0 @@ -(ns utils.worklets.identifiers-highlighting) - -(def worklets (js/require "../src/js/worklets/identifiers_highlighting.js")) - -(defn background - [color progress] - (.background ^js worklets color progress)) - -(defn opacity - [progress] - (.opacity ^js worklets progress)) - -(defn avatar-opacity - [progress] - (.avatarOpacity ^js worklets progress)) - -(defn ring-opacity - [progress] - (.ringOpacity ^js worklets progress)) - -(defn user-hash-color - [progress] - (.userHashColor ^js worklets progress)) - -(defn user-hash-opacity - [progress] - (.userHashOpacity ^js worklets progress)) - -(defn emoji-hash-style - [progress] - (.emojiHashStyle ^js worklets progress)) diff --git a/src/utils/worklets/scroll_view.cljs b/src/utils/worklets/scroll_view.cljs deleted file mode 100644 index dc98271802b4..000000000000 --- a/src/utils/worklets/scroll_view.cljs +++ /dev/null @@ -1,7 +0,0 @@ -(ns utils.worklets.scroll-view) - -(def scroll-worklet-js (js/require "../src/js/worklets/scroll_view.js")) - -(defn use-animated-scroll-handler - [scroll-y] - (.useAnimatedScrollHandlerWorklet ^js scroll-worklet-js scroll-y)) From 813c60f9e136685d9464b0740ad3602e95efaadd Mon Sep 17 00:00:00 2001 From: Yevheniia Berdnyk Date: Mon, 6 Jan 2025 15:18:07 +0200 Subject: [PATCH 02/15] e2e: requirements cleanup --- test/appium/requirements.txt | 69 +++--------------- .../chats/test_public_chat_browsing.py | 6 +- test/appium/tests/critical/test_fallback.py | 14 ++-- test/appium/tests/critical/test_wallet.py | 57 ++++++++------- .../images_gallery_inverted.png | Bin 0 -> 509659 bytes test/appium/views/home_view.py | 18 +---- 6 files changed, 56 insertions(+), 108 deletions(-) create mode 100644 test/appium/views/elements_templates/images_gallery_inverted.png diff --git a/test/appium/requirements.txt b/test/appium/requirements.txt index bdee7abec64e..eda2e9d815a3 100644 --- a/test/appium/requirements.txt +++ b/test/appium/requirements.txt @@ -1,58 +1,11 @@ -Appium-Python-Client==2.11.1 -Pillow==10.0.0 -PyGithub==1.55 -PyYAML==5.3.1 -Cython<3.0 -aiohttp==3.8.1 -allpairspy==2.5.0 -apipkg==1.5 -async-timeout==4.0.1 -certifi==2023.7.22 -chardet==3.0.4 -cycler==0.10.0 -cytoolz==0.12.0 -docker==4.4.0 -emoji==0.5.0 -eth-account==0.7.0 -eth-hash==0.3.2 -eth-keys -execnet==1.7.1 -filelock==3.16.1 -flaky==3.7.0 -future==0.18.2 -hexbytes==0.2.2 -idna==2.10 -imagehash -influxdb==5.3.1 -kiwisolver==1.3.1 -lru-dict==1.1.7 -lxml==4.6.5 -matplotlib==3.3.3 -multidict==5.0.2 -namedlist==1.8 -numpy==1.23.0 -pbkdf2==1.3 -py-ecc==6.0.0 -py==1.10.0 -pycryptodome==3.9.9 -pyethash==0.1.27 -pyparsing==2.4.7 -pysha3==1.0.2 -pytest-forked==1.3.0 -pytest-xdist==3.2.0 -pytest==7.2.1 -python-dateutil==2.8.1 -pytz==2020.4 -repoze.lru==0.7 -requests==2.31.0 -rlp==3.0.0 -sauceclient==1.0.0 -saucelab-api-client==0.6.2 -scrypt==0.8.17 -selenium==4.11.2 -six==1.16.0 -urllib3==1.26.12 -web3==6.0.0b5 -websocket-client==1.3.2 -websockets==10.3 -yarl==1.6.3 \ No newline at end of file +pytest~=7.4.0 +Appium-Python-Client~=2.11.1 +selenium~=4.11.2 +emoji~=0.5.0 +urllib3~=1.26.12 +requests~=2.31.0 +filelock~=3.16.1 +python-dateutil~=2.8.1 +ImageHash~=4.3.1 +Pillow~=10.0.0 +pytz~=2020.4 \ No newline at end of file diff --git a/test/appium/tests/critical/chats/test_public_chat_browsing.py b/test/appium/tests/critical/chats/test_public_chat_browsing.py index 83caa25b0658..92da5fc7a19f 100644 --- a/test/appium/tests/critical/chats/test_public_chat_browsing.py +++ b/test/appium/tests/critical/chats/test_public_chat_browsing.py @@ -422,8 +422,10 @@ def test_community_several_images_send_reply(self): try: chat_element.wait_for_visibility_of_element(120) received = True - if chat_element.image_container_in_message.is_element_differs_from_template("images_gallery.png", 5): - self.errors.append("Gallery message do not match the template!") + image = chat_element.image_container_in_message + if (image.is_element_differs_from_template("images_gallery.png", 5) and + image.is_element_differs_from_template("images_gallery_inverted.png", 5)): + self.errors.append("Gallery message does not match the template!") except TimeoutException: self.errors.append("Gallery message was not received") received = False diff --git a/test/appium/tests/critical/test_fallback.py b/test/appium/tests/critical/test_fallback.py index 206aaeac67e9..df68f8752253 100644 --- a/test/appium/tests/critical/test_fallback.py +++ b/test/appium/tests/critical/test_fallback.py @@ -161,7 +161,6 @@ def _check_message(home_view, index): self.errors.verify_no_errors() @marks.testrail_id(741054) - @marks.xfail(reason="Arbiscan API is down, looking for analogue") def test_fallback_add_key_pair(self): account_to_add = transaction_senders['ETH_1'] self.home_1.navigate_back_to_home_view() @@ -227,12 +226,13 @@ def test_fallback_add_key_pair(self): self.errors.append("Key pair account is not shown in profile as on device after importing key pair") self.profile_2.click_system_back_button(times=3) - wallet_2.just_fyi("Device 2: check wallet balance") - wallet_2.set_network_in_wallet(network_name='Arbitrum') - expected_balance = self.network_api.get_balance(key_pair_account_address) - shown_balance = wallet_2.get_asset(asset_name='Ether').get_amount() - if shown_balance != round(expected_balance, 5): - self.errors.append("Device 2: ETH balance %s doesn't match expected %s" % (shown_balance, expected_balance)) + # ToDo: Arbiscan API is down, looking for analogue + # wallet_2.just_fyi("Device 2: check wallet balance") + # wallet_2.set_network_in_wallet(network_name='Arbitrum') + # expected_balance = self.network_api.get_balance(key_pair_account_address) + # shown_balance = wallet_2.get_asset(asset_name='Ether').get_amount() + # if shown_balance != round(expected_balance, 5): + # self.errors.append("Device 2: ETH balance %s doesn't match expected %s" % (shown_balance, expected_balance)) wallet_2.just_fyi("Device 2: check derivation paths of the regular and key pair accounts") account_element = wallet_2.get_account_element(account_name=regular_account_name) diff --git a/test/appium/tests/critical/test_wallet.py b/test/appium/tests/critical/test_wallet.py index f890c5983c93..9c4c5c829381 100644 --- a/test/appium/tests/critical/test_wallet.py +++ b/test/appium/tests/critical/test_wallet.py @@ -36,28 +36,31 @@ def prepare_devices(self): self.network = "Arbitrum" def _get_balances_before_tx(self): - sender_balance = self.network_api.get_balance(self.sender['wallet_address']) - receiver_balance = self.network_api.get_balance(self.receiver['wallet_address']) + # ToDo: Arbiscan API is down, looking for analogue + # sender_balance = self.network_api.get_balance(self.sender['wallet_address']) + # receiver_balance = self.network_api.get_balance(self.receiver['wallet_address']) self.wallet_1.just_fyi("Getting ETH amount in the wallet of the sender before transaction") self.wallet_1.get_account_element().click() eth_amount_sender = self.wallet_1.get_asset(asset_name='Ether').get_amount() self.wallet_2.just_fyi("Getting ETH amount in the wallet of the receiver before transaction") self.wallet_2.get_account_element().click() eth_amount_receiver = self.wallet_2.get_asset(asset_name='Ether').get_amount() - return sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver + # return sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver + return eth_amount_sender, eth_amount_receiver def _check_balances_after_tx(self, amount_to_send, sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver): - try: - self.network_api.wait_for_balance_to_be(address=self.sender['wallet_address'], - expected_balance=sender_balance - amount_to_send) - except TimeoutException as e: - self.errors.append("Sender " + e.msg) - try: - self.network_api.wait_for_balance_to_be(address=self.receiver['wallet_address'], - expected_balance=receiver_balance + amount_to_send) - except TimeoutException as e: - self.errors.append("Receiver " + e.msg) + # ToDo: Arbiscan API is down, looking for analogue + # try: + # self.network_api.wait_for_balance_to_be(address=self.sender['wallet_address'], + # expected_balance=sender_balance - amount_to_send) + # except TimeoutException as e: + # self.errors.append("Sender " + e.msg) + # try: + # self.network_api.wait_for_balance_to_be(address=self.receiver['wallet_address'], + # expected_balance=receiver_balance + amount_to_send) + # except TimeoutException as e: + # self.errors.append("Receiver " + e.msg) def wait_for_wallet_balance_to_update(wallet_view, user_name, initial_eth_amount): wallet_view.just_fyi("Getting ETH amount in the wallet of the %s after transaction" % user_name) @@ -124,11 +127,11 @@ def _check_last_transaction_in_activity(self, wallet_view, device_time, amount_t wallet_view.close_account_button.click_until_presence_of_element(wallet_view.show_qr_code_button) @marks.testrail_id(727229) - @marks.xfail(reason="Arbiscan API is down, looking for analogue") def test_wallet_send_eth(self): self.wallet_1.set_network_in_wallet(network_name=self.network) self.wallet_2.set_network_in_wallet(network_name=self.network) - sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver = self._get_balances_before_tx() + # sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver = self._get_balances_before_tx() + eth_amount_sender, eth_amount_receiver = self._get_balances_before_tx() self.wallet_2.close_account_button.click() self.wallet_2.chats_tab.click() @@ -140,13 +143,15 @@ def test_wallet_send_eth(self): asset_name='Ether', amount=amount_to_send, network_name=self.network) - self.network_api.wait_for_confirmation_of_transaction(address=self.sender['wallet_address'], - tx_time=device_time_before_sending) + # ToDo: Arbiscan API is down, looking for analogue + # self.network_api.wait_for_confirmation_of_transaction(address=self.sender['wallet_address'], + # tx_time=device_time_before_sending) device_time_after_sending = self.wallet_1.driver.device_time - self._check_balances_after_tx(amount_to_send, sender_balance, receiver_balance, eth_amount_sender, - eth_amount_receiver) + # self._check_balances_after_tx(amount_to_send, sender_balance, receiver_balance, eth_amount_sender, + # eth_amount_receiver) + self._check_balances_after_tx(amount_to_send, None, None, eth_amount_sender, eth_amount_receiver) # ToDo: enable when issues 20807 and 20808 are fixed # self.loop.run_until_complete( @@ -160,10 +165,10 @@ def test_wallet_send_eth(self): self.errors.verify_no_errors() @marks.testrail_id(727230) - @marks.xfail(reason="Arbiscan API is down, looking for analogue") def test_wallet_send_asset_from_drawer(self): self.wallet_1.navigate_back_to_wallet_view() - sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver = self._get_balances_before_tx() + # sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver = self._get_balances_before_tx() + eth_amount_sender, eth_amount_receiver = self._get_balances_before_tx() self.wallet_2.close_account_button.click_if_shown() self.wallet_2.chats_tab.click() @@ -174,12 +179,14 @@ def test_wallet_send_asset_from_drawer(self): asset_name='Ether', amount=amount_to_send, network_name=self.network) - self.network_api.wait_for_confirmation_of_transaction(address=self.sender['wallet_address'], - tx_time=device_time_before_sending) + # ToDo: Arbiscan API is down, looking for analogue + # self.network_api.wait_for_confirmation_of_transaction(address=self.sender['wallet_address'], + # tx_time=device_time_before_sending) device_time_after_sending = self.wallet_1.driver.device_time - self._check_balances_after_tx(amount_to_send, sender_balance, receiver_balance, eth_amount_sender, - eth_amount_receiver) + # self._check_balances_after_tx(amount_to_send, sender_balance, receiver_balance, eth_amount_sender, + # eth_amount_receiver) + self._check_balances_after_tx(amount_to_send, None, None, eth_amount_sender, eth_amount_receiver) # ToDo: enable when issues 20807 and 20808 are fixed # self.loop.run_until_complete( diff --git a/test/appium/views/elements_templates/images_gallery_inverted.png b/test/appium/views/elements_templates/images_gallery_inverted.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0e2bb94e6578b9f9f363d89209a3b188d33ca4 GIT binary patch literal 509659 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�Z-U|kL?DmRkWR=9<4MbXU?Y+*V7}*^_dt0Dr$(;!)sY4Ogmsq zt%|ozgInsoZA>+`ZW=?|Hn`wfoU5v_mn%6bl<66|Oxt9Nh!hr*pQ|UG(pX)e5wY2R z#2Aq=B4Q+xnSEkE?CI@y*#4fPdzRHPU!G}9CI*9B6n;^N(lhkm(cHg59gm!@XRfCo z@xh^@s{yh#h$1+jujH(8E>cux97oRQCv+F-dx=pV(-dTkSW)P@8i(_H<<*2NJ+WaxX^wnfUVkFbXQen6>ei4tR}uuDZX$QB7H z0$SFfjp7M@B5r6$Z4655t?F96&#IJv-N!0WC?Ia!tsIFdRz70MXk!`nEwUf5`yE*d z5`rc~e26qnN8jxTt0$!e+q4{Z2imqn>JDRvEnuq<;HGKmhn}W22w9Laqm>{O-J z?MO&fXDzv;4WAlGsb-uj4ZO-8rx@{TfDBeO9C!B|k3X;ucPw`+-aX^iXL5`@e|Se& z0#2;NB~hGWJT1J-k2R1Il674^iQJ_U7^9fyh3j=>x7+dk5BFTJSDqf9$Yf$-^FT6a zUExW$iA{xhCJ<#aTa_E9CKF1krp7|ylVDmhyJOG&n>%bj;i4iYN5AXoT1($(e2nb& zJEnE1!6Q|qAm_yXaG-74ZBRF4I&{;4Zjh#}Jfvih1lCEBQp>&Bx@jqL`FgOTgEyH3W`t)nM5FwDQKxt8|Nt}kB>7h zo=I^f#g!}y2+O{I%l(^wB1S_Dn&;;q8J|C(OTfrL2oC2R)AXM6U|m;MH?g`2ltBT1_AHLRm!Sp!N4I%~Px?fL%x4x1t>c+xsC7Vs{R z;>d!=L_yX)vOThoflx9@6tWTsBT*<&fR^Hc%*Ntw`B4GWdcnb*msGY^+z31 zc~gt5l^iKF5={;(ITX5~LmAEN>#;9$WL`75SkNs|SR$68Yw3p;X$?LnTBFcLvHDzt zzZA(7VotaaxLhV4pHG}lGxJm{wpmD;#?p5^^LS#K&S;%6rVvw2kRS?DfDsxa8@hJK z?r_I^^%SEBF|dS%rbw)`P)hZT3kgEPN5^%UXl=*C-40_~jM8XpY1$S_VLm@2vLh}R zlpEs~-{DQID(4KktHM9QdrGPmETzDhnh=W7SJ~#x<828mevW7#D=*USP{L4E zR=zmwZU28XJ$*IyetDpM^)ufP6M!PKX#~Bfjb#cU7v?o^9T(2mnZr2KPg`=Sj~EwF z#$km(ZR1i+bd`-y_%UGP2J`t(&Q1Bf{oa0W|Gw@2*!)cSG#L6SERxzihM1}lm-p4i zM@n)QKkLI^|NJ}d>R11QU*Pus!t!6+v=D+A^9D2gXa=1&)jg%eCZHinB~nV|S+rKs zHIkuI3_DFf7`i4`xEwR7%m}$+n}FR+qeIN(G zS)kGEy8}PG`6IaqGJ<7!WSXBiJ$@j#$eI?!n($+WRdIGB=f{<%(X^drU6)M&LZP+9 zSWVX&#_7!E^2ps?&p-a-Ti(6TTrTe_;XWjUZLrF2nO?DZqE#`BLfj^tP!O9pSk1vI z1c;V3!08fs^Fz;fKm6b9{laxlgt%~g*wM8bBNDS)*&PndZmm-3&T~3F5~JsE80cD4 zCzNO+29#lq8J!CKu0u;hj^mcG_N?oI#A8*d4((cEnu2a3OPujJ5wgSQ!V+K!ilRDn zXAs2^Q^Yw*3>u2YBn4hT5s)-sh(vq|RdtPwRV|INwS=4^xhy0`T%2)kMd=Q$dJe<) z{L>Hr1-BH|C3AiM6PNctLAXLZQDmaX$TGBt({SyaO#V&*qOxFwZyC=SX`#pn_ z#PP)V{3GM_#4=u3=QG}&iE$*wg(w6|C^SN0bVHVoh$5tbOMyTl$%2j*&Q|ZROezqU zD(2BOnp`w7E41!;c=MM1exT_LIR(a1AjTPA0>U^;hw|YK=3nj zaG1u>7)4BpX<2X~5GnW+S)Awb`NF^b+auR`VVWy^SL({+?Yn`TKXAD`(sc@f#=B~v zAca5)h3O2o>llV3cMsojy{r^#aLa|OJCWN=QxqvC;_3)K5T%*7}E_=kVuyFdLA zgkfKH+kR^0FvCboxQy{s7C?HjZ7(>Aa zSNUF2ktr<8N?H>_DE7M}!*>IX(X7``2e~TUQAyhpJ{nQK9#CJRxAIAbwgNC;i8OEO zj!G2Nwrwfpi%nb1nb`#{)57U8)_!}}WBV2}G-zvTLQBb7O;@t2zHVmOC8rmNDz}M@ zcojzet+S9X&1n9XbzZ}Qezxc%9Oyr9`#bF0w>I&OWxqx9M zq21DPw|@NR_=?x>ejZ4D>D>MNz0W@N!dtrqpLLz``hvag&%g8?zwpr97Hc6YFQ`^j z^5zZpY0q6!Mo2+pElRfxgT*!)A*$4RiisE;%bajRu+D*HuIA7&rpg7=rV`6T!Ef19 zip6ME`6Jvsud3ieZxq^eym?4G+&v(Qz&p=)9T|2<4!Z+N1`3t;qJ$*+$mAkn5gSiN zprop*m43zh3gvroJeOkgM~Wyd$R)C@6W*`n66-~g8?ihDQi=#sUf@DaW7+L`Li8-l z{D~B`kX0f&rL=LOfZN1DN{qEA3%mWE#!A=}ah&j*4M7o^EFvPMntjjPIiTSE$~3dV!2*rYXqBr%oL^AV zGW3?NQCL+-e&Tvw@M*=Tg=L;GI+Mc8<@|_JEkl1#*J`Y`cz5Mr{@?$HX}oZ~o|vZ# z%XG!9BW{_wWgWN^WEF;xH}Bo-5pq$D>*q*gq$R8+p_Nu^?r|uxWUBQzUR;l zU|Nzgn5LuYI+l6ie1FI6MtoXo73uQCP$FH|(OA7DE+(`Uq{|c2zdEv%co*=CuL2%I zf>gwundXrcR{Gv@Ja)7ea$K1%CxSK{_dT*?F6Rs9%ZYiKaBi*7y{ypZVn9fX+Pq=p z=E0}y#n^(KObi+4Bg^W^B9Mhe>nb{PtLzjY=E(E;ndeiko`1Q*^Kvd+u2(|HJU^eA z=7nVqgivh;kb)3mHJuhzO9=vQQ`qE%2rbwTd;akKAF7qc^NHv4nd>|vMB(n(V>^u& zk+w1D&JujWZ{L+dX4hGisFoz6)%2ZV*D4wzFi9bTqzG75LCLZu%nS&FXa_=$Ea8eY zhJM(Qbc7HwQqwjTB^7O{#@8_y0+Nyiv1AI8u0QgJKl~HBZpZ1v( zF`_07jiwk~vyz(&YrQ13|15dqvXvWD@>h`9z8Os1I2B)6>5~b?*QC&XL%{Zp3CpjV z*?wbE^Xp{&zxDm!4m3WM_5Z?he&O(bVf%k|l=C;P{_7>`|JJYktC3-*hJH;o|F>SIPq=9x;gBU)X{WLUTlw`XRa%7iVM8)G zLWme+HfZJMX#BcQfAze-3ZM8WF!gDV@Oi%K7kZSRt^E1=ue%J9+4dlRd7WSLJ%EOd zpG5hj)2jzw4=klB6Ww(U!_aX!4j7}jTrX7|LwO2`RY1vwunOE#Se6QN)KZ|8CI*N; z6K~&9I$9&4R8B>$erfuCpx^a;|3i;4Eh#Eef^i&4=^g)I8{V{U3DIDje&LsSw-Oge z3WgjFo$cuR9ic4vII()ivM!`-C=_x@RjF(fvWPMA`1FD6^;*qth1npGm9KV#LMkn> zR?+u8clURnaIEUp0i{))P;AvowUNlZUy0eHG#G6v0pCdc9ABhGZ=AxeZ5f6EDJ9OW z2m!m@fNc!EWTZ~)_lEoXj{RWqt0Tn~zm8BMNKfPm` z|H7aC_+NPQ_JGp5X8GMrLeRDYMoHE&vR(q?)5LN<;TB&xT&f^6w^E9c8QcKrkU!P2*iU2AY@V!F;;rW4ocjBZ+XT~CUhrw{Mw>;e5y z==VKcx8q;`^$+-p#mWs)o+%LfaUIzDLTMSn$5W*sRr6dOli~RU&1z zQV=4OQ?)Eu<`ttAhjyTCkF-s{ao1p7MxLLp^j*vSn?3!|)Sw_$&Q#ZQ+#lP`xV@vb z9bMnk*aj&z<23TG|Kneo=O-kY6c!LGU7L7#=(&5?F&ul8(M+>L>3}u^!7HR_Nu_YT zURW;+)A_`8==j6Kk%wK6Pc_)l+M-p1kcnIb?;k(#`25Vgu7s5MuE;9dA{4f5>8)jF z8``cR7BEfA{&1{(B&pcn-80-j@H8!a7^}+bx-Oj0&lD7XjX39d^QPm?n;y4%mc?O| zLAI9NFmTxIXiTk|oKKP%7QD;EDB0}>-rPT+C5+>hX&PDm%CO&acfY4UzM9r_om2vWm*IdOXb7ZOw`s;ZFX+Q((q z=s2C8Q6lsG+XHvUJz5F;x^RAaMoPi)uqQaryLaz+K0V`|+cJGru2@@WtfXj***I59 zYr4KCZ?N;#&zsqL!TZ3nu0#y6NV?8q&~!;=_jzT+e6ry8}ZvY@L1KbUO1G zPmI&F5wRmN7DV-l#yQXRdPNAq@pxpOPR!#Kx$!BLtO>KbyL4P!f99um zKXE#rG5eMu9v-ScU@07SE%(QJysOVgia?fV-Bcc=QtZ2qVKD4EMW+>=>?v!;&z@!0 zC@m0rQ(?6o&D{g@I&*!z0<~I}Z6wSy8bQ}KHCbphu_Pw9;!;A<5sM^c$?^CD|MbuQ zg}eP7KQ%voGRR5dt6@?gzBm+rl$b8%_3wN(dcWeB-A2e#ZDh!m`ku&~L&i)i-8f^% zg?6sL_l+c50aioMU{tl6p;VgaZ|b*Jmp=da*Qd{~ zefqxiiJ!lJyQhEc`rms0^X-VQy#KYb)UUl?|JL^N?cd*t)5_rW>t$!iMUjglW=YHf?-FkD1Q$2| z&+5r35GW}qw7;bcV(4Ft+yjxxOU0-vDuEDH;$3V5T=1G0BovD%l66U>v>=d(Vybzl zXecNOH?foSBJ_|;CZ@#xpfRSyInTPTNZm20j1V*Y%{d`HQ7QN>wn!T8nKAZChp9om&aPzxXx0DBGk& z$%&jIS_$_19%~irIuW9)e2ftI@Zmi%tX!WzaC&|srNn-}f3Xl~ng;JHd}*F%o}Ql2 zc3}zy)wC!bA&(?KKne&PZ6oPgOV>37k;t+7d)$OoVobE6dOI20pj=gbT$hF2VNcUE z6xpIvq8}Qp)`+x{mIWcgCg~ptp{hhGAwa$A47NeNQKE98qH|nMPn$yL$~ZkTFDFV)wUQ3+Avnj`z+Pju}a&1RTg4d6o+ z;*g4*B;Ms0)gmcs6|^xujj6tM*0fmNqLe15OvzQD(b^WWqvV3pnNk9&I6^eUs6n#% z-4%>(P_lv2kaELd8Vm+aB8C;WC}tTk610#c?{G{=WywV{E@#I1T7}8Ap-4qS5DJ70 zLK#fkp&ElU73P_?iQ?^h~&YSUfL27|D2D=FiQEHVi=UQ1_o#TAD zGEK`z(IFv-DdPQv6b>y`jI=1B>hW$WSRqE%;5c2cJdYQyEA2pq(D^F$-)+_3FHS~$SVnU)%p* zcU=Eo?|&LXly9y6OI5|s0*bGNj$h5w{D!LKr-95zBta=PV5^j(*APg^MNo<)-CkJ` ze8#Tm*A4SLRw;KuJ;_nj38`wy zGO{e5X>d? zo=>(`7~8I)>l&P2IiF92-~nC?e@n{594SRmQWZA2yW7#VhIJWP+(Pgx%R2G&{EpM} zBR~D+-^ej=JRZ5byW{Tej;3kIIdeLlczSwb97oo5rASFApc})wJ~3bKSRU@^8jHfS z8ya>)i=SIok%?Yx`4>S95$7U9u~^e^*dI{RlXGGmuj~#x+O9>Ij+9~8wHR$ktH9fY z)@~CCs4!8rP3Wa8uM-e;g1ViD7(Gq1Svqu@hx>uMyN2CfFkVia&J)Z00a+ZXL{v$% zS|PfQSOm!jnx+bEl;C-K_Y>pwOuK8VC<|+ajy4J*G{Gx&!@$GwuBwkJiM5udX$WCq zny>8omN#$i881)77?{UG2rF6(hOVgrZ)>pT0jqzYu}9jrC&kP%FPq1jLx@_L%PA0C zKuAf~9I$#o35%o}3LD+L1Z(rWur3~>8+OBv7zC6VrK_^w>Sp8&!U#;vEVIYCdLLB@ z^9CbYy6#9ZEq=L>-GW;u#`2pQIp>SR-E zlxfh7#jPuAOk@Pw7}~a_?|bz5LXHtFYxU#d{*Hh8(;sn*W0_Z)KGL=kiXs<{Dphzx zQ1GiGE4eAcDq6c^T@t}pj-v|;!?5Rg+yRbx7HFN2!c)>jaG4M-Ah}#-p58z6^!`Vd z@q!kG!`*@V-9Xdm4Nh!nV}ofMii9pFq%qtd?`gCp`Ghs5PLNYUONG%D5ul{nlnNEY zZin}tah{1OF^)6NMcC8~3xXUn%QE6!KxB;)n$|X0ZK}Y;#@Ah)_CfB!wxIH82%`RN(0H4k@p{NMll&!n7K*0rhun}%ibgteN? zuk(r&8mpTZ!}I;FXL&f%TSX(Q4S^JyahX_Ss3;4qFkQ=V*s~Xkp>3Hj7pBvRHG^zY zO+tx6()~7QBDw!EF%Xr*R<`W1sGrF~<8xw;k;}Yrx{eHe!@e`joy7NwxHhE5Ago1L%SPBk zid@Hy&ElX!&TF9daer_1jGs?U#5XZjAE)ep?ey_=F!Qp`&*mg`R`}J4->XUEmonV{ zq3vrs_^tNp{Qv#F^H;W)@0KrD|Jxh=a*$Gl`1XwU-|hXsZk6BEele)|+m7iAPupL$ zoo_s~zp$Op5(Zy;0Ke9@X2|8+5bn8!UioE%yFm#jg&s*S@bA82_ z@xI#s#_}U2CP9a1fgo)rsyc_9S!ykV5 zj?44R$c*R*MA?xAY_&Los5~WU3TpE@0#O51t?Bz7Ya5^{LU!#yi~_$VP<8#j@434> zVjF|jl9XeW?uX6GuJRais?yt1fY6eX1LO6?F!Xf8KsCKx7{@c0>xt*5_dI@hkCK(g z1JG`8$eXn3{rx?q6vlC6nI~NI7_Vq-X3>%7Jh51d1friwVWs4RH5x4iDFy_B80t-* zVnGN=)3lVL@m_P2u^e0eGHnlS;Hy^PQNm-Cn zCOF43k6bTLPzo`6*4b5F+e zlnN>8Bx>k}jff;f8#;M4%I6}y1WoVkd8og`KT0;@IH6lu)(HeoST&pY) zqKeq;4|_`XEbhv(F3d|+Aq~D@wA-qrmUgx@jloz&DT#HRaegI6PYjL}>M@592(e19 zBLby3lo5DWD5a@Nc+DM3b|4y()_5Y>uejw3E|XRWi^M32bB>S_w(U@+B^7~fEw*j3 zZHsAYU?!ESU1u&e7?~%+JmTh&b)E?^A!IdaAII^9vn2&srLbCJwIGnm!Qt1HTs$CY zj6q~YNrDn1K4oNUQQ9C&y(WTcvtgSSYYkEgath?+Ny!ld1a~DBPo5P@Ta@jXt|Ou4^g*jcLc%aRTH4(>W!%tDMyxdCdNQY z>BZmeHb^KX(NbeJ>xn9?RH5lj(_o}T#0V)-LL_)_u2et0SjedkswqUGj|As%>x|5f zzA30^$ck<3khmCeA>d;s7D>#J5IwE!82TMDWzy;>A)r&DB#9IWttEnllrZ#`BnryI z5+DRmOe6F11jP}2_{QM(_i4BBTZ&rgltOIqp6%QMF(t0^%=1~%S;?{2Tsz6sY1+0! zH4WH+w6Us1YRQW-q?Fry@1<Eywxyjn!ymBPgG#rn6 zv{t-(_l^{wNji{YL>Y~gka7W$5XzANauq=UjZjq>K?+66Rir~{11P+UOtM0{jBRNe zMbk(Sf#9#CI74w9j{|r6f8xDPO-c?v61&pzPshQy{h|x38BeOfRy32+ykl+=0 z<;8z3#<)RdYh|+r8Mm5oslmK$s#gYy935*6oS&=b+Vy&-??0e~s<7Gh%({-OZeevR zp;SZK)n{DDv`s=#4akS#z~kka)A^a*u;a}`4Q5kF7-i{fhcy;sY|SjCTw#nM;M~MK zPppd~`T!+BQ8Z1D5G_(f1c`NBS*DS`(`XqWM;vMEPzwFf^XB15h%4^Hg!7JhnW{nj zIMoT55NM?^jjGi#BM~AKldqN#B3HBG=m~z^M0)Duky4!$3nidftTpJvp1ys+nmq`` z=tt(|$~v8y#}h#$R++iv2ssi`Bmw?tuxPqwWV{VO{ z)`e-hqLrlWT6EKp$ygt@O8I~mim-Sjprxw!+p=JFO_tmrk4P<8+*+48&vhKRUPdmL zE9>f!LcRFT8EtR@Qj%y}d4c=GfuZRbuUBFSq*6#Fqm;%rEkQ!028tniiqL42nWhWl zXwh;{+wQjD$)J=&3WIl%Wm&n-6Vp^7;Rwm>7D8}H)uOauU6(4fv<=m_{^ge7)XHpq zzu2JM)#62pEqRm@^Z87OiFtMStO&v|jVmz;z@U`ChXuc`_+`egBdvktEJ-!UA`wD^ zGK7>_Lu3t!fI_;JX&zBhvbO^?9j<99&JlBhBv3M;l_2;Pjim1^!YZ`S$i;C!&xDX! z))v7^3ZHQqUS&Uj$vd?MVjnZ%pCnF8tx$+p>j@!H5>$bbtF-^^BROZ*)iF+rb8EO< zdoI0U>?~d9&}~54fNmm6X@o2Y@o@`9h!;wi5Mtw?+}z-{9r{`O$^rfg%-*lb^8P9w z+VAb(wf(hM;Fo})zqkJnwATpB|3$5Aeb6tfLT=TzTt)2iW;a%;QPqPjms)Trw{eTF z9N+ey6kn@u{x$pmw|?-KxB2U~U8?BFtu%S7npCcqt`kf^s%l`GQXs}E*WC9V!_c$a z?YKMMW30igRft02aLSQIf|BS5P1koobsN8#z19i?NTKV*U22rlG)>1a9JsrCV0XAD z#Iz|ju6%g>k-NJCTJ6y)(zhC;Bt~|O&nrS)7={CH9{xm8kR<&0_^4|Z=lA=S1TJ_60GfflM>y>$)>HD6h*(R5puu2U&7QDNX zoMS#;5TR!JwUi{c5`4tF1yM3x(_pQsmD5mFJ!43O+bc%A&%~%msR~)li@?PbK8_U@ zR3we)k=eYs(E~LRyonbezbE9<%dg0`_QLNW8~I6Yr*tD&`L%1)zoRjWe?Qu0j81?MKl>6vA{5aNsvZsXTQ zQjAC`Xj+4|TlG(tZDLkUi?x!pwxMY(q#ZdWtZk9X;A6(GyiBCmCDC;mYs6L!52P@Y z<4TE+SR$D~@{XJ$%373d$QfeFwMrrbewkQ(L?THsG0#`rIuo=aS&bAKqXqN2GGERt z%Zv|!Boz`t41tm}QWT65M7MH1Ke3D>(ap#bKo!<`CAt$@wrJTxsvUNU5w|W(vD zq*D!cKhPROcQ{gzl$4p)m3bU%6|jI-s)}%I)mkMbxnz6@O!Le*&n(X2VLV zsQgP~G*(&M?1`Z!Z>+7sk`VdDJ2RKODc&Z$cN<1u(6&wOx4V{-_T1niMj4Ejg$D zI-4-cL%hjaZQa!CsOy&o#v2@xTTu3jkFX(Z#0H_cfg~kcz_yJmqVNK*^dYjWE7NSb zP7Bv-!?kM|29NCm%ElVF8H3bSdAWXn#Sc~mN~*~=w_q{z)v3o<6(Bzz{I@18-zLA8 zPhgF|xBs~ITjtuo2W-E$&)aXgAO5!IzkCeXZvS2fY5AjK&ZGRbO8I#kaTA+gC40`Q$fUN+N9;eeXlf zoJ&R1)Xb|=RXr!?Ist&p-QAJ<`#ZX>W4GIJI2G^nHND#R_gi1UH2?HPt0 zF;=k*sJyG%1iRgirfo=bz&S_THvI6z_k4JK&*}V(l8VFrfL{aAT`K%8IHu`>lrT=u z{LBCNZxk{yS2$tUceIVgH5Tt9<2Z6Uow!^s48!meu-)C=(f57zXIm!b@rm&~a(y}x zCrdx{U=3lZT$Sh?O2E*!bZv`US6ry#7BQw8FuB08E;tv-xgllE;%0J*WHFI()I73A z7)^5{^9w%0AeBTa1v0}Hgg~nMI8A6Pu}0Ch25SwuMEqKX3jFFA`UG7em4wiWSPH8P zq#{T~v3giNI1fJ7_mGx{hXa4;{)us(xLz(aP0Ma~sP|UPC|O~F%e-(b6zaE7SGF zVYugb&?u?^NA#XCCr;0gJbrkG?FJ62@=lFykwp+)wI>{%g)<$x-uS8pJ-3LjGc2BF#rb12&UAYL!~#~`=MG<^%oMt_OLup<3I zoI!U6#oDhLm4tTQ_uYb^+D5tM6XymAF@$B-E>a+_$g@Y@%gbOfF3B&aa$65M)l6|D zaz=L?qy&v?@;|FImdB1E+V|#-?E7RGKIjydsLE97piH58)*t+I^h93?3p5@DZpqn6 ziA=4-o@N;hy-8}nLJt9@!O8Mci*(mrlGlZea~*Tt1SJC_V@POorm4D?Tz}YT1~d7H z(Pf8fDcSR(_4Q~nX=Q9gvS)L?K=Ryf#VHhR9$>gUt-OVdKOfK>`e5C5mpTiB$x_c9 zzh5pb&g&stEUJ2$f5ShqwY@iO;f*>I5aNwToefVr#aG$3nAc@1h!HLebDE%wMi;!F zd!`hGPd&h>-g2St=&EQSseq$8x{R4wH*Qi-?myVl zhXo)q6F+(}BCa(XFvS5zjHHnzLM$~Eh*NDdDxzXyUm^_+fV-rTn6GJ&f$c|}KShdV zl3is^!D|@tRO;n1AB$sLHds09z*JuusriL$&pwzau#$!75I~!Z*nX%M?ck`bF}E5y zC@NSV={V)N9_kdtj1>Ki9?&}_m@tv4ZLi+^H%`j{C_U&7b?e_-2_!EcewQ|2S)rmA zDAE#XI`s?Fgs)*+G8fxcD!vs_VPuC?v!9@0S>@M4!c@v*8VqTQNH&bVvM_!6Zt;z) z!#rjoc9#@P_A)f_B{QUWge4h=k>7ME^cO>}f2S;qMqU$%9*sI=Bac&nxHHfBiq7Xn ztNvuhRT2?8gjUk}r=?|kkyGDG+`vMKeW-qX)W#IEwHNvJ&*IZ1^|IFy>gwt-*IrB# z38c8(1aYF|>{;aXRE@)MUQj57Lpg|zIN*C5bxS-M$Y?&~Y$s-p(ZN$WP3}!z5j&cM z%YB(&f8?-d+uD{KA+;`=y8e@FODt7+txb^)3yb|}3Hz)l>>>h517cNw|1A22FwJG3 z+$#0`F0kMfiaIQfNKaxLcb(%V>sz=H4~COf5={#Gfy-j@UtzNP?>ZwSp&#fzjT5ovgxpt7*T0$oSOEG*X760@pYvUXdnUYq;Q%h zSNP}!I6o1bSEPt+G;%(v9I7JJ-4!Y?R@Uh9TPL%DY$HxyCqV-Fs+L(6=_{5!p0+|F zTULol&l4uc(t6w9WtdrAB)X%$z3YGrG1-D+4E$zT=T1h>&%=JjWX;DlQ2m5hE)g~= z<>`V8^vTr)E9A){bKfeamc99vCs4-aV*Q$4M%Hj)gdhC5pJOjrl+ZQ00*!IJWq_hl zEl}t;X_nQ+cf)m3b%jd;e+$S6(w_74>8R#^M5zDM?FsHJ)LEL{!*Je7d)2kSsJoz zg9|DWW+@8@TU{zUo2rUow4dTW)I5Hdh?d@lt{)4GPD}GsLM#yPV83?p!N^^Z=Q?kJ+0g{u2x3^pIDPsC1SL7(w z_)?4OUXV!_@df$D=~{>P=TS0TkYCo9C3uCtYhxDi7YjPCO&{#f@C&1C4;3VEdO7QPcJ{ucS2alq+m3 zfnBN2CVTV`QIlaCwZzlR*+XlN*g%!K5@e7VD(C4D5-S63O)U*IwB&*! zQ#K=wt@d}uTWvHW(1Be%HBOo(WTOfVPa9Ry!Le~&MDIRHT;(M(KsevY?i-gTjc&%C z%{H28441f*9|48obn*B9UIgbIVbNFv7yeQdFed!7+!aE1b27yB&a&~3Z>)^j{I5pb zeC7#roP2jm4;)T(h%)>#kC~|odoz*Ck~SPB39oR!p4H$dQdrDE*I1%+{1y+lFt$_2 z<$QMiA2`W)n!P~l3p^t+r%ltoUL1LI$oBVDwtN#!lF;<*OS_*r`LgcPotu(aR_@P( zt;{Ha2atas{h%O$>^j!0-*Zg(odf$yAX9hFgU0-~2if<25;gWcL#^{CS)1Q|yVGMI# zmd2^jt^|Wxmd)KlP?0b3_g1$os|seuN|PI)@otb27&!vo4z~$6$?T}WurYQz$Yiu( z=0eldg|GR48py+Gz#njjwb(}+Kg0s`mZjR-ir@G9b{%`>99Lq|fRj_uK^W>L5JF#+ zoT7V_<|GG0IAAPG&(AOF-#m|1v63iINs|wqs?`6PNX!lz(VS%< zdag9q5;*QdY3%I?fnTSl;+uxzo z?(kg{nQA0E$cnp)j|i6HwKt@5_cH~nNpx!e_x zgNk3S(-EMWo>IR1Im~y4cTSS~DWOM{sonP_&id`dr_Ja*w5Z~o*4Sw$ylOHq=W|?; zFqsnmEA5b-T~2KHd&ec2IZp$IKjYuh`#ZJHEBTE;^|&C1FZv|;WKD{CDYNg9Yk@$M zaepTdt!&@d7!DBY>W1LD^$MRa`7AKET_V`Ol8Q}I1!4baXwS$Z4V<6D%_V!u7B>xtSJZ|- z*ZCH+rp(2EfvE#2XjCdA)M@hn%Eo77sv4H=#w0kdQRTi7T1PO{M<1r>8S-1DQ-e&f z{5hNgzZob?!|l;zK&syUNKWIj$%mI`)f=%vzF;s_sw!LKk6;&-*G>_kt<1k|f?oT+ zSe^-hmr0Y5VViN+L7kn7tL(D6G>WpEQVeDyf8C52Bh^TfnF|vkdd==Fjy!{h(+7ms zSeY*WRrI`lGYe++=Ts{6`a;AFA|GQfL6?EcAq~atVj0*fBrV_Q-|Ry$(5&!%k5uaz z-Y$7^78}puFe)6pwEB*fK!o#^O?K@Q=8>r2tpvn$CT zi+o6F&uh%9OSW_%QvV!({a>?)1I#G!pf(IzA*WRF&R$s!0ih}f%wS6gI_%Sz=!@RM z#cZST%+KSRgq!6z!0}1jhGD;KaD%Ab&M=Z>s*h!)F zK9u2v-bG@SB)0lLF;6A7d9^3yar=mbg&PUBJ3B1q1T9!Hfg(*r`Nb@U z*%~JBMt7-dNU`HY%*eI#Ij*^C1?&^FLTxiMP#G9M4Ai~Vk`=XB&mS0W3_Z3l;Y4*Y z<3}~8bA0P5iim(JDx>UG%*-&Irc54>Cd;Vl&sVc0tcq}wtepHX3}^hRCP0MjjNirz zb{B8?J4YRh7+kC>J|YNJ1$7&4V`w7#BVQbuhnD+gh}jP8s*o12JWu!)6WCCCAeC7S zKs<9rQTk+L6K%Km?NML3)eUQ;j&=hNvhByLHwmg4s&+3#$e?BfbCG>=!mz4O_VTJ| zl$LJM1;P&}avlud9c%DIvnuX&9^1K}Jac;*HH;=6|+4%?IgQ;d`xXed@6|C`wbKT6K#!C7drLydB;7 zEk4rS8sGh-R1q>V={pPwWwyi7Z{3xa z`a|=oBxcaT7KG6#u>V4ehCh+(JzcH6)d%?Df5jFslUeFCf=p%h%_twjLSYzEH*Di3 zU~y(u6qrn^KLhIzs8Ga?pLZ3&Xm6`u4ji;%>}49I)k?gZT_;!iw4bhVRSp;&N2r3e$qILNIg86w zn`$SLW7{78XlVT|&1cF_swGw{B^)(aAC;+k%qPGbBIvhuGGa^D77_N1BBGc`ee|J^ z7Dzu`4T)`=en1Xy-Vpc1+K}*J8B$UKAgCniPjOUBjB?diXR}H>3CfX@?o7xJtQUMI zSsZ`Lb~@q%R|{>)O`)k7e$+T_7;9h3l)M4p#MRY1!e*ed>x)+bv3keX~~70l3w zROLuSdT?L8P>J_Z@g72daFL_dQY9u89JJvS0`WZ;Yq-W>!&j$LweV5`$L<+z-Y6(? zYyC=EQHLa_ICn^WxXc{g|CG@r9L9|OE#|EcfQJK--JG&YB9%88?Dl|*en)t{lVeDq zR~r}cbKO1xFQ-*Lv@jtLrge>Nw2Wr6Xrrr)6wZ98jv0+z9}$-1DYA;ZO=YEC7kc3z4Q9GOe2Vyd?@_Z?-DF&SAeCO7h;`S&RsB*nw)V6D&F@_Nj%HRY1z><)xHzy6|S+ zx~5F>xiOg96T7lM6I;KpIT?HkI8gEEHurt;l=QFm7DRtrZ(}0w05|yJv&752Rrd8f0$Jz40YTZ~q*!j}iOXXCmzK(RBrojFJ5`D(_FutJ$gx8kNnSX=xH!|MSiA z^^-Vrmv*C3vg(G%Ud7+_$!|kopXbPr8mYXUL87jm3bQdnsb$PzpA2nSFmd=X)pcZR<1xDh~86BAx98}3G^@}(R@L5Vg}Fajlvb~D4T13EG zFE=}_8hdF}!2P~fZ)kV(>%J{oYm&p5)v*vl!g2OgG@Yd3@)b;oaHt_fr{H--#S9@= zej@JjEXUWr10HH-ZQRQcrH<)zy=3ApIEk17z-{tu zsp&dIycB_1sFs5@HJNmpFqR7FscMG*jkyKbF;H4n7ZqUVLk6RQ7<9*TmXE)?^w=NC zcp!-;IDX-msh1=ZKT5l$;IvNrx(ZNa>3N!=8{}(~p25Y?wf*Lu19P0sT0q$q&{T+@dV(XI!a8GK18M zb5^kh%U-~m@1VMF zP#W0(zM#wpS5xl@HOJPoaYNKj=}Hb z$9*r)-`mQdkFX%v6RC(7dix`J1IoOwAUL;ACi382yLPa=aicdl`)MdD5xoi%8oU|cZol1{2f6_4Y<4Q37WK2;<@A~$0m zyh_jr)8=Cq>8cJ9VLi{b7o*$0Lx**gUdX^203es8FX(%#x~9r*0J~k^&3&(5KndSR z&(}m&HaTw_y{H;$2gmA_85jY#50Z4WzP6g!U1=V?fzS5SK{xdC{YAU$yX(icJOJ{DBCe+-(Sy?<-?Bw(_EK5R*MM))gv{hLMKO15H z$uv4Yk=Y2jj>x~r9uBiFo1MO)*dsR+61d4o=Nd7Hp^!u_4XGv7Q&qRbVX_1%wo$CS zkm?S6qV49FeU<$-1ACq~4JJJ2+bHIXF>Xi;Z=oqAV?MhN6^!swqe~E4ISONL17$#^ zq9oj$9i_B?(u4L}JC@E4|HXfu9IGt0s8!zXnxO8@O6N%8l1*T-B=1)!*Q~QX(hU|2IUB$xaEKk&LQ$C%jSG+N{)%iVnU3qnM-zlMcQdMGC0T(D4qm+g;3@`dnMKLQ`Z6bD z>#dy|#e+-y$Sd*6V`bvGXfFljgN8Jw`BX%r0zs7|5vW8T) zZj?f0>~$B{O+Pn0gWD2hpw6PaWoDbHj;4!kbMV&BlWgDQA+F`Qv^gUZhA@_}g3jUw zZs_j<6Sz~f=kjZobJ47eeLOKSgyV)J!jM2~CHU|0 zafmn7aNDb#$uI+*dN`}cVl(|}z%{1lfLLmuW#np@(cz)@MkYw4UQ-1^f#bKHcfjjk zm4_=4<<%=bUPM>>W;+qtSO8y>##A>H_epK%M@|VF>U=LLZJ-~l^^*v%~8*;=Vj<~-fs$yBm_?HO_gVvsU`ddVU@CvaNNpSf% z#Sa8IjAVkNbF$Iwvq0!CkbxM6p4NO5JmBw#1%Z9c)RzqJLCRM6@b`IR1-KPO>|eQv z0w$tON!n~;n}Egwuv*qxhW;;Q4-&UD=-21(_49|QLH;Rf4#h8le6x)(rZt^^gA7s8 zgj~wrR5LwnFP$t9HpyKGPvm*0{^3CQy#0Mm)c;DVc#Om_ zwf2KOLC3P(8$2ZZr!8Aiw1{R{Z61WeMvgmR9Ry|a`I(3pmTsJyVzki_hs4*Oylx&6 zqmN6wl76eCioyHgrxygol^&jqt7ZVXASyLCmtfYGEL0DM$Tk@K-aYt?&e1L8hMko+cYaz~M8M%DiS3qys4Z*&x)zgK@l$nlMH*G`1I) zjkz#zimY`mMD!DJ8sK+Ec5{@36ZN}}Q>CdVaCE42cd43T zjSdgjP49Bs0dy=_lus; z_Xx1Sq3BkF?g&-`&P=+W9$7{O^(v+?vR$#6PW!GHZ_cliO4n6VU+Es=+STkV#&;j= zWCBfx!vY?!vs=FO{JUSP(;EN#ak84R%z#~R{ia_$=VnXn2*@%5h+dwT9UUXJ_G$?3 z`R8XsNbeL>8ppeLIn>^~ebt*MH(0L&Z*%6}9$s}2wCx#Lvqq3t5oEUjD&JjKnkD%IHqQX*m>Y3lh=BDa=)BR!YV|43S!0jUzT$GN`XTwRnD#fw|wX}Ml z8u?;%Ei>MhJh%Z)Qi@D6diUyp<;4-O7yC43_oc(EQb;9K768sS{Lhk5yN;P6Axgg{~)gtfh}3Z+4UUlEE2}C zBLF43aVkb3^MoP(I6I&`3G8d!u6zZaz&J8l3B3NEY?!l^P=r6{q&|U=kXLiac6(Qr zJ~84Wo4c^v{8xISKW{1uTGSZU#4JZ@%~TAYzubR;zUTmn8AEb_jjj)lf<}XaEzHma z49m^yshyz_D{iO(E8cm{v1qrFDjV=}+- z4WsCa`dA^PW6_2juiEab>5W8j6pLSU?4-(JL_|lvQi>*Fh%F8+TZ>gQY6tjqZ+hqI z0X=71@CJNyN|imAsJ(Fy743jk08K zuxKhd@Q;}I3)POQMTGkiZjew7kwP=ZA9pZ|=*LW)N$f100aB>B%QQL2zWZg)E} zB%KAMvgK!q!`-HTc;tiMfj*>XXJ(IRYJ_pf$F(i^<0FtG`}Pxiy@Fasm9=lq`bs%o z%g9W7qiac-Dut-0NP?{iV9rsX;I!}Z!{sSU+N^*a-9$o8LYrg)A@eAoJv6rstK9U|%jHEMbh zyXi5ROi!mNidJn3Q+)hNQH*IHYbyqq_?JnkPzw99$-%W-2 z?L%;d#x+|A^D0#mH@L*96lcmne0&vd-tKFjro1Agr0-# zhlvJS@6L{34l(ZM?z?4dF`n)*YwHI2^=Kic91v;&(P@I1G(C$rl^H?Z6#FcOj8qP* z`~Ph9E`DL2svA)d`_@L7&0CF0wRfXF_zd}G`H51vJ{YzS$5j8vDvgO8jxDe4S>iK!7!j_Tku18v(50Q z+S@({`X}`yNsM<)Be@ACBoGZni7k@C4}(E+^E^t0fGaCN`c&=VrQMosrHT+ z3o3ssrp9pk7~*#yxCKu7>EXw<3DzWC&3Uv24+SkWFkT{N8_2lVc%Tlhqn(Mpnr}i{ zL9%VtrEc-969IGy@CECOXDRllg2@{BjvZBmTmV?_@R5~r!=F$}9fOjr+;`!ArI!Ze zSC~&;Yp6Ln`!8g`uf&#I;WW8eK|ckYpQ_3G?I};dAtlWujlns0~~u# z^+tnX!Cx-LzBN8A0+X1j%a&cdBH25-A6&%{NU=>hEM93Fi}cNGwj4jFv9Zb`@ct%%Scyoy6zu0siw?8lrCGP zk)r)QjJ8uCYm#(wQfM{siasGXCt58`K41wLl7IKbm3|!r*7fy$iZ9XP6e{#8HXNW~ z4!(Y1{K-Y^PINJxUM8WdQ38{RRM4Kk8GmUas3b7*g&h1ZApTRq9$jEd=^ibF3%JSp zN|K(A2y5RzY6lm%VGeI(aVqVG^k!z*6K8(tX5%36?W8@f-jtr?aU+9fhh`1fxSJV5 zB9?>xiuF8TqVUh$+54kS4P#=c-Z}Jfe(a7s9Px1FVa&hrC}a2*;jUl;5<`M50A zE;7Z(jiL2p>geeDK=uL4`yoD`R-6x`WNgcC;@V2Ia6g4EHLjxVbOK7)ClV{+~CCxVT4)~EInrQC{-}MoG6)qhDPY~<>FxJ|mS0|4j(k3&gjT`Wf^dNxJ4xaV4 zQ>ZuV0N+VpI_42Ht4^H2kn&aSAW*s`gp{_-)=@$k5Utvpaq4$JT%rS7Cg2}t{X{b= zne%uBmP>(R{dsY+t}?jJ*<>eSUBy}7&-qiViuVjavcE+8M3GnVu9)Cv_@ykiCif=_ zZ)v*X!{+N`>3pvq(Uoc4tNRgZD9!4%;_`rjMjdxHo}>$ek>Nl`k1&9j4mix za2^mG-@oFIT~8uI7r=6l_g!@t$H%`5sdg66u`9V?v5ek;wq$OSTay`bFFKTCtY!N7 zOA>=OfOb7+@CZ#a4~$RK@AiE<_cu<>K&@~?kU<#l-A7RM+qFtVKZ3}Wzh1OV8_X6E zS-cPLbX(?~j=$^&cjeFUIB!W~zA63Qrjg|n?KYA%6n24u)W=zHf5y@jwi}b4;argK z0$>oMw|4F)ZM(&{0`sVPI#J8i`PjoW^fq@hl#0mx+r`QGQabbO*R!%MgO{b|$;FS; zTVk(?eGMB&VQll*qD^3eb1VCeS)W6SAmPuYA`@c9GZ*%gyAtt!F=(C67 z)}4f$Hh!0f(X`4Mo~O1u(EO(PExW91+wI6{ZbR|M|KHQQ%+QD+*9 z&6THZ%&>=hsAiSE!eODo;|afB~3jlIvtm@jzqOwZX7Y%FPv@6 z9yyl*F;rh!r{nPfhAU!fd-1lr858vD)oGHcoDm!9U#v_gl%@!5NKmmuz8bSJrUOqr zn*NF4WAJme(5=^;kLSk`HH+#5t64?tebOP#; z@)woyZNEfOZ_xcz#5KO34^@=hqv6c@PIba8Wbhs>wpT(6Y1F>5{tXi)ndKuq;qKF7 z-?BO_#$eC8hX$H3S^^5Lo~4vr{8i;xnGu{_f z^OkU8<7Ys|E^J5Chzi@gUM%W^$6~F?!q}ccb3U8CEMfI*aR4z9uYo5l;s)P0zOfdD zIuhH~I(<8JbecnWFc+sd;vjVEwNrZi=zwY-DEGvTR&jN0SVkg=1V=3LdJcKX+YZ$v z7uH&@_5#i?%3mwk$-{YLOv#m~rwDDi7Gu;tRK=MqW|G6i~>QZ~PfZMKb|8GtGvT*NDUj7|yXZj6qu1 zmnebh5N%P8AuWQBYOm<>z32uceJF`YaWIG=#MZ1#)g4Sb&>kDsny0ng$uK~Z?=mkr z2*wXjXI9t9uA9YO^)}jbTuLdy$(m&T!)!NE;8HPWE7wXT^>zZ;dnGGfR~_v~$b)3| ze0@+`{jbw*@Qm77qgjA&_aPX1PKlYocLHayS}Y0cS)VMw$d_+?&0J8dJnLl(zcC z`nMnLEBBNbl-!NXwB{&ugXozlTX&t5DOtx~0K`tyP zCJzSg((+%TII9%*|A~^T8tQJ3oVk`|!Kg3c{f7 zoyk>ggPPIcfWV-^pxw0n!(f;1mzfrAkn3*u{+cFSn~U{NXQG;IuXb#1D6-5zHjqmVTaRs}sx>V&h;K6?G0QHKQ(r(k!g2jnA108EyfEaiW<&N_n9AzKpMxWZfYEiN zP$^Oo>A9hQb9lwbM4KfbUZ{w>BH2R3|+324Oku@)~siE=k#0tK8A zLdG+FenCNNz5)4=g#+&>cJnn0e_~8=?#CgxF|&CPWMkNpv{KW~{ZIJ?35 znkt~7+9;g~96<=B6(SZ1uHr8;Ra4tmZHtP%>}=jHnew9NQYuJ^2`(4+u5ubaQZqvtF5=)^2TO3qb51v!i?#y- zuk?K`f4>1IfU3_0;`>+9e^%G41~>IJR5ydd)0#h zK%8@ckOZ>6c2G4Q*NoJ_^_ksIus{_x(e3Yg9_A=rJT_ZMY;TqFSck%}a1}>CcqF;0 zZLBmF38{3zD`poawdX2>CtG^T_=L&E1Ns-Mj~wdd;)Rac`I1`dBnv>|!cQ{4 zaVtw`&Ul4D=5EE>lWkM==M7EkTiAD_SUqv5upcSbG*BC#L2^cBJReh$Nd}A!!mbEj zT)o&o@-{Mz1&O0JMW)Fcx9%8&{tCw<Y1hh;pM+>IjN;phY*sF9-O$ zOLnFfts7r1R=YZ86`rIv(|@S8B}j3c7}H}O)Ma;r>Q>@=D@(@ALHOj9Te?L7h73&vXbjau_*uv~a+%aD^3HU4yegw{Ri*bL&BkFGDJyF7{ls2wt<$91RSAjp|3)+u11VUkIQQ;0jy);|k3Txy zLBV%NQ+#J3CjDBft*2>lZe-_afV2k{l<;%ZizbacV>G)u{lZ#ka>YFLC$6Q9Eq0Ge zQTy4N0Z8x>|DE$)#=)N6=B?1&P1D0imt3EBvSJqZ&N-z$){|~R!8}U4H+pdQ_~d~% zj+t+_Y}xE|DY2@f>ooB1HJ-}_-QYZK>j!&^^uT*>%efzmFM2KscI|siPWC`18{a}= zAhvibHeS{Q$|mI!9}d;Y6UUB}#dI9o!sufpqkkv)=J(~Px>YeUJN1ldR^jkk_Sb>_z^Hh5N7yRccH1WpSKanD z-TE0Xf_kMP969-0O~*@%^0dEOlzGl=jA54a^RU`)E`qXsi_pknO2( z%dEFk$!a=t7M&$tvni=Bsj{4$hzA z3?P3NYKrTOKa+{$$Ta(3iA73)Yo*9Tgt)JBd6QtgkmER6P5H!HwhBnYh*W@G6WyW9 zZ^TyK1!&~zM^(ee+WB}i(D2P%-QqCm)IVB{@Hm&aLNiNLXjRH-j%Z@N^YEE$CFg5< zKIYM1E|e5Hla+8m4B!Pu;H{GzRV4oYix_Pw8HR!sD4Jov2D>QJ_cUOr zuf%KJ^^s&Dh1Gm$cy%TTw?uSp^smgU7DUz=r~R~n%|_FS2_d)c7qCINE;*4dwsTSN zeq_AmJaL*TAF-Jb^vlWlYqr;~Wn6?E^4Uw#1ju#0w7AVs4krahnM`5dg|$cm2Ej|< z`F9S<46gkav|%I}VhKuBO6}&3ae|OsL>w5T00Iw96u)|tOxu+MUP+h1FZr_tjxOl*{*a>|=FVU|r5 zKz-#yos_E6bwYxqnRMo#9$CMiHW~l4J<-B{e38JtYwj~F%Sg0r_w#8i{QAq{IPzSH z6Y-ew?M&=-WRJJlQ`zM_dS%T)&CTtTopHis&Opy|hL0VQJ>ARQ?5=V*qq5yriCs*v zfQZ%&S z)lbXB$Ft|z^lW=Eo^GHI(XYAWY4xWaalfOzdiId}`t;nFH9WL_X~RKp+KE=fdZ{vI zBS_XFE+0lyMz641x7744(^iAQ-@OwRnJ@{Q4KmIgZRjWouhu5*M2{*Xudr6SI@SZK zk0VuLLOSJh*(hsi3TY9*X&9@4B{hD+FJh3mZy1pJ`T6|=c9=Yyg##bBX*x;?ft4y} zq%`)DL)Qqet=`U8BKM|`v8V6qGv_KVbK9~o!4V_FFz6Im$O@|+49eI@=7$kNbNa6( zr*M}3DhK9VWy6hsRYdI4rmCV4a#d3Baz>}sd?3QHg1?)yGiG^=&h z+#n?Y578&-3;M6|C8F3g_k}#wTc^}WHRp0i=gf%iqi7Kl^*_7h^n1n*hH|`9t2CYSE=T33CwRW(~lIFh4(y7oO#~5wqNK?$BbQ1W+ zIXQrqSI_e-X7~!FUrt?D?ZEoevPzz|L2CjRDVPkgcsGe~1Mh^1VgRtM4;`V@ZF4ah z@lN`@5YjLIh}-Fd=K;eJ6oO0kJw4`E%Ag25Ih{fQ#O>IjUC<8q14ew4Nj{7W3yhd^ zQ7uARQ9qO}OKD;{mXL>5ZsQ;H7->iZM0J$>}N8Bry2Q`w`+A-CS#@ zqBdFrb}GiK;}lqPkw#m^5{~PXlC;#ycjQvWlU?mlpFdhS!YU6rpkXK-7SCz6pITo` z4HCm1sS+6kA%3On_Zt>PiEI2$CKo8-6-aE}w+5G!A4w5!IMPORFDa&zoQVrghOdui zIFf8GEg!y=&-{(~p8<}p&5criBQDsKOM({;-_A_!KBz7nrlY70Pp6DW+0#_I;THJ# zV%4esDlSqr(neHT62yqGt%*Y*YllIRb71W_c|lJE^Efk^%%e2Jl=_B_jc&cB zZLbWcn6VpYf7IvuLh+>fso2OqUWi(B=seU^^qZ%X;h}GmJnzDkZaM2%$}GuUV*Nz6 zyU_$G=hBJL$3wOkINLeM+;!VhLEH254`>7SUaeSkrEL626&m?AK4ANyrUpx4=bOc$ ziuu_Qao9aD2?xSkLX1zjd~>%x)9+ZC=hL^&GMjEIj5^~aHn&#m50!{plhrMa(UJA9 zc)0~&pZYG+Z$;!f28C-bY+}YoYzuMbxl>H32y31#?U5Q-o?!<$zk1iY#qZivMd!by z8zP3==SpIdi{Ux{^1$vUh2iElW#!#J-nT8~ins@ra8~o`-MHIFE;;x7jHnGeGQT@A zYyqmR(!SXE8v1ZXe^5s?h%QqKmwCk+TV*&y@~|We)b)^NV=DdY(#b+zm40v<&1) zM#BF{I_t0|-?tAdrKB_y1SF+%q#z|VKwxxtj*t>YN;e1&kj{}KC6rXU!{I0aX(^Fz z_&wkE{g;2>*fH+sey;2DIZqkz&2HyfPg?-0#%~5f9juYv@LM0;d6~MsOOa-mRK!MD zorv^F>VMK6avoZ^Oeje~oo-j6E765^vYpJ-XOp!`n9eFsw8w=wr_{t` z>A!E2`f@@_=`K=6!=nLzcm(kT&ywJvgPIDAKDa5PbrPo zN8)2dQB}ZEQ&MiEOHUX_+qbSymuWgS5>X#j1CynyBxkHO#nLxOIKEIS)F_-*fuxA2 zj~-{*;hP-Ex$lIN*rfUyOC;A*H!^<|>|bjC9chA&W3AkF^YXRf zc!Yoz?=Kl5EsFlZUhz_hXl5ld6Dp_dX&RR(H|?6lId&oqqO#~ubgmzgN?X}mDV47x zhS`BHijoH7!B+?dqe!461bowaB$5#BI<2jjYMDTeI+rGGFGe3 z{z>J|ji)%B8YBO`4)(Qec`b*nG!339p8O&K*a130f9)768e8b$w*GL#dR>XvNNzXd zVNJ(7A(PqrpPr*I|6z%SBEL~RGorpSx%>q z>lwbUUMN7|*DgX2AQX@}XUfV+p_Yd&`d_=!67R~1oOjVB791rx0>;j(IZppDT~GJi z#*kgQ_(#Yy|L8#@bhWYUzMIwc)?X&T*R z(!50$p zPA7?9PG{FC&AWbZ$>V4=McMHa^|b_OmQ{Vr6EKm!DrQB23ivJwS6Y>Lg}!vA0}oyq&WDF zPoDF3dVs3=Ps_neYsQHrai(jf!CcO{5Li+f%jrf!6Yuz`qg{Dlkx#T&78F?K6jCN) z@@`i`-5Fl}yV$14555SlLL)4#%=M#c1|&2WP8+XZ#x>}!IcA4;ZXb58`DOjfU0GSA zKR!%JW|R@?y7_i_)lI;livJpx*e*y~M8n#aCIJ)_udSVi?oBsVapbD2dP$FV1dN- z9PcG9VaGV3nhj?jWOhS1Q%r^C=>T+&yRQX!yz_DngYdr;ZREIeQVs)To~Qt zc8-XDHP1c&Zs^tjE%J3lPZco>`L121Ja>ot)m*lVq%BAGbGwqvmim=3r+qvPcj)%G z*;!f@I~Jei=UN%BPUVk9v;Y0rILNSNTR6~DeXO?}SOdG~P-#sdI6VrQthMRo%{V0Y z>t0wowV$J5vzdm?+^%gI9~NtH%^DwZ^Pl{nMjeC=iw35%x?;tdOnfBq%cPB+L9JK9r9?PMC-b$s_bc) z2S_HIF~4ysng0f2FSNOJja6NtMkx;kh4Yf1O(-|&{ZX<(F`I;o08~~-mw2(HLRaKu zaBR*%rd^hy`K!a56JQBUv&r^=BodeBt3Ls+l0lZe@*C2h^6F^_3PrOUb}pq@cqmtx z;Td2V_baeY-1z(NJvtra03`xr3gU`~8>wiL>_Lw?6K^YaJ!{m^?Oax{J-qT^hIcpW1Qi}BtH?Wc38M)c~l zyc_zfuLV_Nl()>H30#=;A*gH7TOc z59SUIfU8S=l37=eq#)zLLa>4sH-@9I%ejyV#q?Gx(J$A@lzUofmn~bV?}8eAw*I4m zCrUdJ?nsKOP}Z-I+|E2*<3Gg1W-N=dxS6&DTpsj;rK#AZXF6i*EN5QNP{a4Rwc;mSl{ z+f^+J_gnJIQyIsm_0y^_X*U}`)Rv;^qt(^j;HWi zn+u!yL&T|P9#cRw*~FI(pA@vCyN#&0uvZrCjvCHq%%37>ai(!T1k zBCP#RcBcBJB3h{e{CxU6#*6Hj;WRSO?1IWGk@r;)i?$$qgd4V~D9%4BvH;>0^Xp^J z6cQsBSj>0bl_jVdXt8++Q=9w_j%+iI! zf0I)_xu0GPyyk?k4;meAqk)BM7d%5>)}v4hKI>NNveqTO~AxWjU_lt z)fa9Px7T>LP|!g4VPjpCrd0ca*O!+CKc5y)II?pd3axk-e72ZU} zNYEdCn$>fgcOC8S*s!^M9wHl}(tiCf&y>d7-(K=A@8Is={l?+pBkSSblE+V5-&xLf zV7F~;5ZS6NcPUssg)@_>h@^TlQ;pSpT@zal1|TUFjydPxYKN8sqfIjONqgJ9EX<_y z`mcp5QxPXvU$Bv+*h(VzQ&}e5{8PS?VIfyv*WHRHAdmaBMTO`VrQVW;5%rpK&WD~k zidim(_IDM-82)5EtbWEQ^Xll4XL{v*>#vVq5;lFRTBdiJ+>Uurp1?8@7$xsz@| zbJ8zRf;D(wCT=1HJPDELDtbg4EFaUlOv+m$(pF~W`vsPgI>g( z9UluX-`;7e^HZ!HXNoI(YxnxtJ<}B5z1Zv#8?C78m0$4QJD>%0JWlO?(`HyPB36lO zfBz+2US^WE@aSlZi~Xi0+HntJqZ4EyRY_V`^C+HYNoAr=7hti_C_DLD-rXO^n# zrhPS}4bfb7f+X;)F^iOxrP!GoeZ)ObZFEFWeZ?#0#m+NZIBs+A>f;!@ycqqW{;Vvm z>9wwnM{}VoUV;b;X36(dZ-@HJ_Sm#(E82eMcdp{gu`K4b%TcMslJYwLg2SS5W4%Jm z>s=S?h(yiiskObvRg==c!xG zf#j?P+M_TMV66rk50atq^l)eNZ5z43oj;nQoD2PwdF`v7YX2#5qE%k-&-s}!LO9YO zRGK0&!2`E5&69W)vJOOYC!3~IGdE+cx#kJyYaiNi&&Kf)z`)~~{>)tVxjsL$?@$Z9OpZ2^YdJNU zXsB&u95b69vz6_t(Lq?LMrL@dz@N?KzKrU$YjJ zR~$5Gxe~l;#8t(;%v59BRF8?Y)5z(MwM#6iZd75S0{h30)cl@n?kQ@X`b+)Q--~+Z z>|bj8!h24nY)Crs7ovw5S(~1>4Yi?5$^LWutAXYd@3I@e)?C940-HW)*J>}ZzbckkY=MRC#lX;u}i^62^+3G&dw@{ zfwbps;10I~Tb!icc54?T9nXmKCmKOP^K|?JlPo-I@bunfWltMDBv#uQLddBsIOOxD zVT=r-jX-^SpVHu+BlHQ2i)s@ctGOH$EvrJfb=bRxR_?rC3)#@TzX}0zbCLZzIXI?c z-xhBl&6f_i#iSHLk08UuFb4e3e#(d)N7@O1FoW6^PZo{~V^tLvv=aM$ z=AOyMn~fdvhd8zrGjb_(IkYSgR>B2`WL3{_g2tp!Bi-n= z7pYcwSI#qMQ1wtuljke41th(ZxM?DZ6}om6BHC(&rLQ#} zLW@dY>(h2sW=s|sy7>SH41 zhaGY7h3AVJpL+t~bP^*eJ<@sep-4&=2q*1~mIkhlQ)^Q50qgT7g z%%Z!c>^#-8tA{rqI)OEo*Ju@IV%<$3dRiRC9!o#Y7!a&!S8fBX?D8r_(^bUdVZI*_ z@@!UbK*Siz#yD`0@~&jJu~7!0hTuwLp$`MB_X=4_Bw5U3h=^IrnV_?qPldAfrkNH` zCu0aiiq-ohBP+A|jS_xnH5W`dqUr(Y(6XPvDho)5dHu_2*^!xET46(aYb*tod>p8F zNTh?lG$f4t^74IUGk8w~-Kx#ZKRC=wten@>vJle5IaeibHoI=pY><-1j2NaQpIGaD z%dmZ&ehaS4rhTW;^UJ?c&#<_6Tvm@SFaJTM%iMbW-e1uLKPm>e+Vv&W@CeN@VUqJ_ ztSGXN&p^jbbk}3YE7-x*^7{NO@!8=)b5P;&Mc`C2 zsbe2ac}guFhWQUuTnha9shU+{EFd?EcnwKQ<&$io%PRfZ1YRds_(V71Mpo5YKZe;M zWLD2O?%Jkv*KfsfLEiPYnRI>l)HbJoX1;uqH{;_5WDyM+#R`yt2ZY`4$N-q8Yf#4* zPBwWy$KpRPle^tEE9HGoYI@vHXka*23kMskuQ~$xn`r5}sYUJNV8pkR^?Z@f`1<}7 z#eEu4AO6sQms_WgMKDV_4F&dZNdqZP#L&Y1wF>`3C5z?H26P_Rlr&#fng8+KLcg-!e3=i03`_dcK({uZ&(S){tL#Y>yNO zH?B7y9Z6FK75_O;53@7x#pcOK3tMs~Wb<-CQ42n4!?lHQ0Q^AU$T*Pr)v@NC5Fr3{ zmRrbMZVxDMk}5j}AiS@2+11QeTWdyj>~q<({zKuTMSM>ddxi4x;pr~I&c)nR81a<; zNPS{I1J#e#JY*U4qH|R{W;3UO7yo#xD%C}Ln2MdPvZ(t#N?ife^?*^b2oU~oTzI1^ zT9(O%lMZrfdvmi~*Dgi>bzxBlx@39L4NeL?FFR0Sv&q?%0*n~&!u1Gr9AaGp3WTv1P;0c4c(@bNw)zLId!h$nmE*^E5fd zSlPYGml$W!JRaCjc=^Aq_8Fr+=W1StTbmtFZw;Cl6o7htL?g$Z8Q|t zSX|NQCTzjZ7_C^$-gy9m>_iNOUy0LzQI(~d`F493>MnDW4mXwPRObOctBhS?%S5E> zOD*~1>2dAKPw#4B>wyfMRQ+(fjbfad?7nx+)@(?Erq{2!1*GOGLSWSBZ;i6N?t_jIjXwcSETFn{B#+k-9 zg=T55)fesAWyhc}?p0`*t<5^9_Hcn$Vv9egbt!lvSRfE~@}K(Cz&r zp?8JncXaf(rR;w)Trb567w*y)?rBlCYYR67WW;Sk0PiUQ6FpbGkY*2IJ?`aMji>G=KP@50?6u>-TBei$7`; z8%-IvJhN5#`xP}MW8cYrC__Gk|OeY;MlB^5qGd8M2dY{8Ym}-|h$zV0I z4oeq#E0tTJICVAJ8rPLnpWdt!7SX4|Mo1t>n$#f#LPI*DB5S-#Ze^2*B~+O%x4}Xh z!n?GC6$M(opFm|P@RVeC9?qsB{|c^t=dAvQL^Q_% zi`T6!WdPz{H_m~q!#w776ayx(LVXXGjt^}{Mn+PM?T%h)n9%E)4N9!3zt9y$7y88O zKSVMc$Kytb(%O8NV55-D<@8}wjGQGq2Tj|{nh9hZ_63Jbyd+>#@*Fq({CjWMt;MFR zt4AXFGoYdrJi(rr;Fk*a?;R)f#|MwcW7$QCR7dFHcwoL9otz8;??7e8PZ8ZT+9yOz zI#6bAxsP{?AeqXGn_!#ulsi{!72oErRxw*f(n-- zgsG}F<&|edj!2Us2T3(|kZ-}kf(GyBx*A~#pb}I(y$7nG8DopNY}S8I1u^6Jf?2yI zDWhR)e@UHobDftsE0(7;q1I{Nj$20M>EiS? zj;}`N?GbG?Lc5iG#+2fc{)78^lJHFF5F4CKfWk$hcGj2rL63L4!5R^DMTy;THS}Y7 zR!g^yqJr$Aa>G>Q5e7s!jDO_waUX50HB#d==L3w3v7_6hUANvRU^L zF02d_raAyGapmX$7gos$Z`Y9)pn3r*vmDBab$8#L%eblabFS57hO>UMR)J6k7{39CP|O-Y?T(AHjFISq8|1n@#7ujat+5Ad*`1|$F>?Rvvg|FC6 zP9>dD)GoJWvy9S)+=w@wcyxovFk>RJ^AY)RovL+acV4P)iy&|Fuqu<@e`MPsMqgA)N+*YDm?s^RNao$Y93rUJ~cNsNxY3 zM-N|09UghEZf|7zkbuo`SWx70WRc%%LO~C5IeT}J4V}n+FeX$q^0v_7kBRPn#n-j9 zGRFV*MQHtzrqM9UXUWP8GC|CnnFyL3v>~A`wj&DQ688W|toxHTUlhzf3rhp`K$$PH zEF)Q$OELDqfbZdfi1~STMv}wq{_OHHx;al|6p?y}5zqj37Rud{a=a0w5#0t%s1%@{ z6nq~Yg4{QTj>)nE2XYpvL;9ouKXC=+eCL*2mvU7=LIp?%e|MDgRrn9EYrN=F7_W#P z8CD&w9w~(p@wido=NJE#2@aQp_9Pkp`hq?>W{m=+kNJOhw@LRGj3Lp!>HRI!%;2g+ zDUUM>*UulUtwAKr8D_aSR(32I&TViFr}mj=B&%s+Wxb|Y*={n%G$&`)CGDJ%)Q$`E zj5%B0Ql78!oZ5>I0{~O~!J~KKTFe{E(z+v;VC}f?<<#W}Em3flJehXX7Eq>J2)VA! zQHD2H!|E_LuDy=@P4=9HliseHe}Kkl-wyMsuq-6y3zHDdJ-;R4x~S0!VM{C|=3%1N zxUB84oK+%DI8sG+BS;fXgs>g*K&B3sBu*PVNS?~N{YxL+^9`KOW>`RuZl8O?5!Lg2 zVpYkkWDribkKC+SME_mVcGNOwfir3`@mJObIxx)3vfp%bgi9Sj0(zFSI=S5 zWU|W0NFOf)Ys4)pd?`xDR+8l=6Tv#anat*%g{a#)2YOAOwOF6LOih09!C&~7Hiub8 z$LLT~5kVRC&_HegU`!_%{_fqHr?t zh0+W1Tm7l#yk@H2(YAC<7&_fa(n~T=JkQ*)r@M~Mmfl?qefWAbmh|;Bk`h;MQl(e~ zBkIRLn2MpEq*MF8+F=iR2V~#@eej+ywg&9$r@of>GEDo_3xErCbR^{=$$zr=&CPcJ zpu`DbZS4oY;A40X;cP$8W-LuNR^}dAXqMyb0oP=&ylZ_mfuux<5cMl;6`XvjUb?v4 zP7$c}b{zmr?gGQ)GciBNT$wp7q*jhj=_mWG#T2^{TxICd2KG%mrp+{;Ty10E#^hMh zpk{=!MB%}{`^AgUAD4f!u!knCGj}V~235bLK)6u6Gy>A>S_zYjEwAOOYh4ofn+)b0 zp3=s1nS2^dx9WJx%I`fOCb!5df2x*U;Eh*<#U|vNvgfLABCR}}vzeCRv3cmdDFEIB zs1~rdx!*-;o8m%{KOsDj8s!h)H2&cI@(;RG*1Ff1-eZgz(~&bta^Y`~sL1U?=7#+%?RSq$I;$)9%f8N{-}BK}h&CGw8kxIK+-Th2T}|Uh9*@XPZ28q9tMXt&V1R#g6&y<>34F%UaH%@rln`(FyhIrU0!? zz&6KqNY&$2a>APW<5&dYmXoy+v)Ri@|44118$SGAD9x0GDfIJdsIDG!T4V;AWjUzU zagTmUdh!d&RyBwW#w+@u3Arf?!P}+muOx2O%?|8Pf`voz4ru?9BrOB~8}~O82XOdP z?HvxqyPsOx7nS140P~xo$-WU+htR&5ieO{%cTNweiOGS`YAk1*KWBgjLLd%{lrJWF z&R%;g1rS{Vt_lbIun9cJz(ZP9F`bSq6m@L@ioCJ?_|{10&5NU6zc_?cv2MH|^ku2f zyt4`4c{RDsH@1PgCS!xARin2r=8yW-cZDH2TkOglx%*36f8M7 z*cB${kp2bAy_#YFtZBGcRB6S;;!iR}0_?9~1WshE(~tFMrOw>soQ>d?&%qJd2KTGV zGNvoC-ljb_F;?KDtt1mH%t2DCP`%lrNS;XEdvfsSoiAutYu;Q&P_ZA*TJj*9EB~AU z)<@%FW^l+Nl|MD^D%afiQelm#^1Y(-C@SpB__KV*IiDosWs8nJqU@`DPVsCboq|MS zjWwLb9&0c5=cOY>aiHy}q~-nKo?ij%Rf8kUm4$4CuDd|QE*rDK(50ClCvSbsE zh_(%6cpA1;Ab|at|nKVEXYU*b!{u!&rU2Rb$$2!AjWr# zXDLknGU3SFUvsYHB=X1Kf8)OsrpuZ-?ZoytI14%a%Ifv;>Y+cBR?;-bFDp~yeuPnP zsSl@pBL7P8Q5GgB&dX_bpg5-`da_CXM}*T+zqr{yqJ6O{tSM`;M%hGz=OO)i;QB#! zEj*pbl~XluqOLPn{g>Zy`F^0gLvYK-TQzB)j=3{PXnR`nP2_&Mywis}=H=1X$EOZ< zNwMh0e}N2e$@oXxR&Ix%zl+c=I-=0Juv$Hr3`TZB zIqNNmKdPi0)(kIpt21&H81$ zk9?XG1L4S3H{<=uvN+Ll17mQ{;$PprsO1Ndz6XB?`#yS2Y&%MH%C0=DHrU)4ZBO{M zxai^Qt2y++3)q8yTU-nXzRm_BJo}-WZOOe_pt3ZlA*uF&-;2@iKutV&;xLf%^E$KV zG#5W;zwQkgX0U+|1c)81$%7?3-bzUe16_Cp2WiX>x0*g|kWFCh1=I+~4or(EIxs=i zpDgC}+?lkyK7Gfn#2r=h-AIu)^WfLPC7SU~gx``@?(3iAq>!_xT3N=zfD}iUu*aM< zy!n(P@{@bM1qYmYE0a>mGwR^(Wcd(dt*)@p$iXx9&4{Kvwz&wD{2P6#hNeC}; zs%X^6`MVgiK@voL#7I4(VmQ$$JhC`N;)WW;A zmwy?T;=k6=cx~889+t`6h}|vRvx&UI7}J)4q8Jpd%*GKp&Av5tsE5@!(%O)`Xb`&U zrd1T2>)^W#_32My`AXS-AkbP!IVSbUJa1x@?{iJ8F%IvPaXnuwNI3cyI4x6bR<}J^ zk&#dq4F>^zZ8g^3NRJ;VkCi~FhBv}XB7O_j)!oX3@0foI*MkV~a%rd^0f$k0PSW1N z(&q(w$AyPB(#P!$353h{+b@C1ewU|Im)4*kpztBNIcw?Kkhwd!f26q;yM>N*G6N7G zg$J|5^w)(BV&3JHOiHLQ441Phu*fNL=kdKZkBCkvbynud{^eiOTSwj<_BrYaBSXv< z#iciMMsLGt2^4^mDx6Q;M2B2HL9Hbzr%43++X5m8tHR#FR=!@!-s1^db=aQ+{{~fc zenNexv!3Te;dMe24%X&|$MW@&`gXc7)h2SALi_NaF9Ts7rNtgVKX6Jsc@D=Bbym{Q zpq^iH21`)iibY`U`bWDHjT1^!=*2LRhfng@s2c_ps`|@@@g492=m*Du5rDM`h;-IQ z8CUarFZ^{la78OEOUq>w;0kywBMom~we(mEkc7AAJjA;Yc15w37p!h5-=s_CIrbn#h3dN_{HNvZJ*bW@0`P7H+n zMl3sUW0qDEIxrN7EXUh#cXvrnMvtBB@CiBLTq%ulV{$Q8Iy~t?Ld?CQ?Xx^vRTO6Iu;W&y#$VKNvUP`NoFdJzkS(!IG9O#9I$!bKI%lj14}$s5WfflfwwVHZKd0AljwD+~mnm(OHoQPkNn1rXZ76%&p~6WA zJDx|)-dGX>{rPOuyX7mm)2L1$3$VY8c&(O?3y}xFfh4_~YM9;|eE!Wn z(utuxeW5UX-H|q5-t_uak*~`&dd% z)*5`q1+M?u_@|ZXlY@1RoFV~9nh0)RD;|^!gsxlevXPN8#U(>wrg>6NF*#1zzTS&Z zE7_2^t^}>@2_lBv$PKMHRBtus9s}!LMRgnbE=F0^DCS!ggq(m3}RNP6CTZ@TN(>JjEyb6d!9> z@XeY_v?Xaev^T-bS&oHsSW~a>PmVFpR6ITs$0wet4i$OF1MV9;Z-M>!|e5@P+PpPBF)?%7}AXS6YZ`iez&Ne`x8S z=aPM#duMNQ=ZJ>+#lf4P_RCXZwTj?V+WW6M{sHlwNvwAW@cmZH<-qr|F&Ve}($2bZ zi`gBAfm^la`#q-{mmyc)F%z&XIc>;_M_2IfE19qSe0O9;hZ#9N7R_@_x4L$F7XBx- zDJU6>yUo0rTGYwbyJ3rK`pzXcaRSr889s9u&6Uj@=z+V8^`~6!5>w+ZzKQYl&)@;nEPgjBT7_UHv4N%%`$7r0QU7Djw6O;P70fYEc>YabVBHRFeHk%@k8Lu{~LVzedWo5^ovnR+8d)Okiy z>@tngGfmk&8H_e5M*QU~ATxAVi*gZS2nB9UB0>qO9D4D+SCi)q2O>fL%}!s~DRbu4 z+2376AHZ);m?>&F8gmOzfqR25{kYHGRlvJjX<*Fh>TfUoQHN}!v4`H6YTEv9fwx?C zSb3a*mg*mfQdkiw`N%WS1fj(DySEc9jKT3!QKVR9Yq1$eMQ`A;3lVw{lO>J`Adb7F7;l*X>Oa5e5|GtC8KlD2>xnBV<>BNI0rDbvS* zy_b;bRqAkT|NG`B-RJy~2=?dN6_npx7M&gwZh1vkKW}uE-v3Kt2A1S56sj(2oq3lO z{BQ4!cfhYS>EW^=Nl)l4PWJw?mk-+ujhGKEd2bB4`-&25rB6|boLxoXKNUTwzcuFFyXZO?!CjlF2uGpqPE6C5^z3(k{HbAi^es>IDdZp zyi}e~$V6b*@?2G@5Rc^KHm{KJUv^hEaIPK13R2kEzv1Ro!pB-je`W8Sg7XWk0no@n z#_tp+-2T+Jes`Jx=J}e*nmNhJ-3^wKT|Y}3*a}&n?~3VR*dFIfzkX`kao`cY_4dme zfVui){|3O3OOo|KcIg#l>iC5DCz9nyr{8@h6t)!kNid9Q=IuN*$=4OnP3ld2_@kK@ zW{A63MP)-}cAz3C#Q*Wv$mYI_qF&JPwdivAra$SEzzEw(M&^2EPxA@(F+Zj)7|WA3**ZOfv% zT(u7exV3kVK9vLO?`C+l^4HwqU?bz3t-PMyPK*2N! zmly4CcXFQl>V*lC*=eNy&N2A=KDA6!yBp>Au5}{!b2$8}`TUgqMY;RZN;fgp(NULY zp)5ozZOV41l!((S^V93dmr)$6cG*{c(~*@`fwLc4vv*J8rd6ebIs|-4>Ah0=Dh<@A zupRX{DNoXWRJEE1ZJ76TjnJXYw-I9e-F=M2J^_zPK9^@Reyc(ZZIHWN7cG_7xE1kO ze0@Zt^EM#9#?1D+`x*B~RbCN@>r8>JU6v9?=vN%7^#Sp0|~mAf1wWa#eJIQ0|pT#ifiVHSxoXm}InmB^bg3I~7G zHpkFMg`P>7y5*pPQ`~B-@n-MEBoRkwgL*uNMZcCd1i`0Mxo*g5Ub)tE1VUT8#tRec z2gp(=6xwT-w_OSJ$&Pa)apHzKdY5(6;>uF!qMq4EK1ydR0yl=2ozi;{_kQw&2d_xI z$x%*OX&JZd_|B?G0#_I&YVwD^nbxhxXhB!xeSYc(&RG-nT8esq|D96?3qYkDcTTsi z=iqxF-^yn{MI!&&nLBh#G(-qX)B+h6TYAqo5s&-h!t$U{8OO#x3+Xx{bSlSM940cZ z;4#FZUF;-Cd7&AcxXkdoS4uNNz}-0{@Im^(gNF|usJ@odjrznIlU=Ip=`Tk%Wo)kj z6tZ|mna~HFR=$3k%jaN?=q6r>L<;(eJX>~urc*nPt2WTiGn}DHEIiEKP~Zb1*^GfT{X$&I)3$&J zD{Ud^>yRZ!*D%wKeR^Wxq}7Km%)jI9bj9D5H>6459u*2FiPv(2v1_Y1y{=M$2%}HJ zJflzqqI;7X$(8z}g^5KzyeVm|k306URLV8n4V?PO^ zPG%X)u4Kw;*g|gzUtAF<+iE&aYJpU$*8>8LU5_PgwN$CRA#pAsu}&2RihY+mYw~L` z==a~ZA=PAt;d9e+#jLI;NIWCb^irqh_hT+ttn}Ar%4@0S|L}A(-i_CP|>eVH>F-!_S{gw+G`=fBPn~kw;`Zg6`Y}>?xM%mq z%YVat^btMIY!PXug#8@tEr899lUbp*^e``ncldFGgRvk?}&S-Zu}QZ zh6@6>w@3BY{`O_$z`{UvVD~Z5da^X;XP3 zxmeW0vheXsMUKGLfl}^73hM&4NicguVW$sXjwq=RcCQ7{p7(R@^@Hly2)M+f7Mcrx zn&2vddy$}=F6+R~;v19w)Ln-sr!?*D!`Z^;6wzmEk4B^jmn5OgmVtY*`%Ewh;yY&AB-_xNlWc?YR7l+u4EVRGY6h zY#RA%9vo?E_iAFl^Qj64bDSZSpu#ArJbUD?R#=fmaZG-D>MN4UNT-A7(|HdAswo@? z-0E~iZA%!oYxTckWIemYfFA1p=NMV#-p>xYS3)-@<>2)G{j!#=H4WcOyPXg#!(U3= zk2=2hR~A|ug}OYhXyRE|EzFi~r}phz6y#0gn*Kgsq?=ywOIJI~`R9{Fcd;kHJ3v)z#&*wZ&4aoMvm0cvvul~Zv9Y0ttR zOX%#zl&VAV%Ba0X6CQ=PWN!PjZ4EXIulaPqz$J+_nguW96M7|trFqqlS(wJKl>UiX z)<1#qE}fU?vgr&znLK@#>?=j&d*h^G8scYb#4jatFRLPqQQI2(x>#8I7?%&X8JOW< zxDJxwnVDsTPQfL|_(;NjJxVT zu7t2(pqxT4V6(NMXMl}9jB#TmLYnNrK%mHJ^jv{2@D`_M{Lx!{9Q-;;s(F|20 zOpnJro&}(GzW^|Tg)o9p1dB;biK+M^z4#(ANKAfAN?O{Zld{nIO!@D@l82O(%Cu}M z^Czt;6L5U}#hamaO0N+OiuXu_tx(>ZN9B>bmpn|rjgD_ymJjzC?;`Xg=~jw{v5I_( zYbgt>`A6g(AD$O@U_R=sTn2uZ)Lc$pr~R~<2!f6%5t1+0)r_K}ig<_h8-Dx0$VaYi z_uk&(BdpE!A#uM+NK z4bdi9sJ+PU;%2{Ekh+k0x)IbvOErnd~FKnYU@9E6WSm~CDT7l*|=MqnQgqH z5Im#)ReEW7tH$IMKQ3Eu|22>_%4p@A?N%NQ4;_9+A3OBJeqU!L-L{_SI89Vj>U+8f z>Eb8jMT%HwX+t`UBn<4ziTswW_EcoNQ84Bx$Sf9{22pswp)x__7twho^+Xekg;mzg z4f&P##%yYGCflMMI6Snjle`9_hLIixHV@gFFSN4W46f;iH^)^HRK!@RR9FI+cwUYk zsYh2#YXRl+1-Z&|uk~oR0upwOTE4aOA&hMm>Z)B#dgs+Gzz{f!uC8-HJQ*lG^&JY9 zyndrCG$U_IDA)T>vDKkj-^DSsNf+h8K_m$2{8Y(#gGSGY5=9LiJaPvN9~pX*5qc+>$}T-638(ocYj48N zz-U$YVQ`PB84II9n4>>>JUWoPESx02k+n&PK1tveHv8l3Q?X@lz*pk2q@>P)ROIk;6l9p{y`w*6ixs*==_p4wE{e@LUJwaug7bk>^P zp>7zeSG*oI+Uhb1Pe|L7`PpCu1?<20g3!ud2Fk2!MCx8T^fiT(fH!_P^a3C+#qR7Eh+DL`q>$rkRaYnPKI4Boe8%cmUOeY{HysGmhTp z`qJ1H>dh3O;N^ARIF+&*iu^ePbmRQ%HDE?)-^S) zMWWA^?QY<78aSPf810y@E0^=e)8ooAZ5Xp*j0Ypa?`_?PTWq1ea5#?iea}3vLa9{J zq3E=svxV`X7zQg~W$5s}7mdb2v?ZmkEUN?zmm+q>S{qLH?-@_`l&q;mv&D_?K7NPc zgjPqs`{4&3pH_bRuLHmR&ppK%iqmW*ah|UX!;#bJPO{PBiqREoV7gvdCb2HJ-AH%1 z<9PoShx-Hl;OM80?qtYlYJ!qA8B3~~SRfTesTN%|l3!+-CjoZDQ0Sa+YL{){_ka2$ zhxR?f{OON> z;&}2rJdA8%Vp%SDB>%}~g)V?@2Uja4$!2l6PIP8PyM%7DL{*il657IWaP))4IzZ){ zwn)qcG!@a16(tS+Ek$ywtXp7U^f?@xtZu14HjALr=+2 zb0&pITqC83CA?&{!Mbf+rl~DVLXGUYUc%Ft!ufgP;}1`a!-2!$B!w;#Sc~m6MHkkz zfKwdqPJ~=YvCtoSjwdmca+^>+#g%dLGX*;2`hLllRs+Zn5#$kk1c}{0?DpaF| zUR)E$@s9h4_neL+rRkkrXQ)b3$rz_O-3@4?2(hDbK)ZJgqvh^?B-hN-r=Iy5sOcA6 zB42hJziPZJ%uNUOH^wTjJ99#7+>cKFA5&)8Hm>u^`8xA_@Z1fSVI1fV0k;Nx-(fvi zE4I=#*IS1fs>m?+uG=nw_*;OEFXPMjGQNy|=h$mLCBM3rrrq5FIp^k*EOh=-YwN0M zbQVUFI1~$R*};-h>P^=TTCqDKJNm1M8HqbIqL0i-#*9w{p;Vq{x?gdX%hC6CX4>g$`mI+ngHG6nxNiV-!xwl zsv&1uK3BxL47!j*p+wmv-zX(Q8l`IK#u;O=Dq~H?I&j`{7!MpzC;D!r??%S4Z{`jn z+BaI$y934wC3EaYy3Vo8k!=m+1k1W&l*K5+G)GFjp!y@`?#R~6KAx{<&esdtI_|V| z5AN@&@nqLI#`}U#* z38xIs4;)VqY%UWv(0)X_0o5tASLj;U<_jfm7*&W#0uuG{j>Wx4{Q*Rq|(IPjh2z(7AZ zQ2C}S68)H5#YTzE!0r-Mm2TioT#aHbqyn9HSOqqLiAmm<9NFSZrM6Bl^uq{Mb2%?S zrBq8PrcuUdxl)jX;rZtu_dyv@;lIu+>ma3)QU#YY%ug zGW6hGrcM(nXS5Q%VF;1S^-Nr^#P!0qPNcMvixgX`0o_?lXR+RjrG3}4E;H*gk;_KT zt617U{+>}6-re7^%rnzGqpMI5eLv8TM?xwrF``<02vst?Vy=Ytd8*2`exs#grI=6( zVGZC6zPD)g(m4{rtwL!nUFA|pRdQXj&Qzr+S-NbwRB|miEY5gxDO~3T<0sy&fn&(v z5F7dsq-&Nd+FGf|5l}UtNN6fXDU|bAQ=uBH_E^)Qm8F(MDp@*!IkKz^%EA@`Dev?R zad@pNl4>H8*|m(Wvy6v(j1icv&|;TQP5|rF!+_ZGpV4SG#NMzHsi}?*<;~C+@?~cA#3F`Q@4Rk8Q0o z@3cVIT3;>bwMsV88n{dg&sWd==o#mYe%|n%7n85fqmAPwE1*?)Yb$3r)_N_k5A?I$ zfOabfe;P18BDn-K)&E&od>nbR`6^HD_UM)D5te3Z^!_94|m_Z-NO$GQF$| zTHT6lFABC-P^-@EB7WM$7y6 z_uSo`7!L!rC_>!WwvFTI$nns#tq`|LWhIxDq%BDsa+MAA^?YTT=GMW{bh^ViL&=F) z64D7Z91eGU^Yw2z91a3hLTLJ#3)6Jw!-ogne|TWqX0~k>;B!1cT?COEOR<))73O84 zWJ5`oKmO^=QxK}=wq}+oFkd(MaJUXt3x~r%iYwc8MXLkj=()T5ns@Ji!#BVEhHw7m z8ADf$WxCFhb0o%%93w?lC>mug#<|-?sI{Z(4mbx|ca&T?pRa6N;ds15 zDJ?l>TWleaqJ@h=OcuIs;Jy|#`sTuDOd*hn(?SSWV$7smcsief3&Su7br0w|$wUk` z62nGJk;dkOTMUP#>pP6oq@pDXLus6KbZ(&UpmUiRBBciTJeEQX8_P1IO2RZsrmbGAv2$zc%s-V`c36{%k!jGwOa8C1Ze`4Jv8bVto*_Ux+nyw5(&*^kW z?+3bm;M?!MZKfp_=X;b&R1|d&rEUviYSm5ed-{XNIk}Zmd477N)WUSV0GeEc?q{r& zFH0^g^U^e(q7$akkUxET;=ld3|IYvMpZ^p8<-hzFj;DcAA~A0aW5>2FOw*MZS5l62 zy+xZ7T3bqugt+nawDS0A;rWO7X0cQ1H9`SeYFtJA$V5Ocr&g>~dz1l<61md}ch|-G zBf$1&>4JL!_7!f@x@~ycT9IoJ)(b+FECrS=a+y}1E}r|tz+v7P<_*_*d>`ogDB5$Y zUgB2N{t5-a)?3x|rNg!#|I1$DmjTn?mkjx3d>LQH|C7cGXnQpW|A-bTvaFmkDMo6Q zHQgFRPR-+DpKHs@{Pen`wm-(_Vcq+DEZ^4VPAni&*9O>3Ga_k)n?v1C$6RAr>gma900WjREx zynu!A#OZV|HrB(y$4@_qDMs4bB3f>aa6-pPY^!vnwia$|jcF%9T<>BElsT~Jm2C+u zQzXSo4vl)Y1qlEi2b24&T`%Mu$yq32+a|{lW4wtU zmD1Rj+lJEQESqetE6y2?$DX0@pulvU`0m?pF-md%^vw1A%o;ABW{j08b1jflGq6w+ zUTb3uPi^lHfcFmHdDgYIY^%!d%Of&}Anu;pqqR8M3C+#o{Q>XAbuA@WmVhaeL8p{K z)tx%)2q{t4gu>GIN1W|(ZlG!h#(}F;Q(2acGA(%La8^DKRf#j?!@~pj4|m+(pP1)` zd77yuQ%a`qJ3f5)fMO%XD=8Xc+mPhuXt;mywQlZs)D{{%kyB=xMAX`iBV+C`MnY$` z@y%sZ!pLbG{LXv2_Fk8&Q3jmr>H9;|U2eoy2@)$>(VC@HS|;1edy$)C=en+xTJhd7 zj?!tf#!1UwYZL~hE!tS=?6l4Ws-Ts0Gqkn0ScqI(r619&>;m3gTfUmolq8Sitvsi* zvFSu*I>89MLr)>0@pTYZ#dFP5#Kt!pMR8e=sFJEDwq4l9KaH*ya0IZKs?yAO=R ziLhkCDn=eDXN(ae5r9%NbrMkKyPkgR(N3eS5(|AzGZ>l##P?33DQ+2X7NsT1K*Zp! z>vki1)Egb8>w2-@_a18<<2Z0So!GWOtpbL{|DCE`{`shVXi_}-9m;Q49g@*J6`zgODO-)`&+@=F$w{L&bM zs?xdN?~yAkA#q(c&eO_e30#-JVF|cCFsy-bi#TU-m}YQAO*H&-3G@voYJXA4st4gZVs_ZVvdpyz$VB7OY_YBe<&;isUg|C~OZ2!L9 za@h-T`#w^fp4IJEF{VWfDJ5&1RyWqfPLuq54{OYBR$0+#w6S!)!&=9-iR+nCLRVbY z3)iXVba%vAp~G~2N9QfpXq+n~Cy!LB=tHcvLUVJv83SZ;QKVdnu`;hK4p7d~`+MHq z|AxLhp=e#d6quJQm+K?O!G{lbEbGMo_#Yo{7S`9x6%;qnb~?W2?zCrTdFE*&#+81s z+&|p&sXTE#U&XdRD}MOyTmJ9qfAaPFcl`EWe$#TLwzgTRtnmo)X!#Lnt@u%?hqLg#>P6jkA6 zZ>;MErEoZm^!-TK67#$g!v^)hwv9Y~%&ey_v0OvsgxifHVrA|4bfchZ$bbKPdn*Jsx2mAI{J?e^7&cl^Kq>wjU%8-Mut9m{kj zZW}cUs46ivm&j&HWHhe#nBJp1M@gBmY@lm%_*8GG6yAHfuDfNHl^XD!WVLLM6Vs%5 zxEJuFFgVwt8X(JAiZsS)eCO!B!z#@d3n>KFb!J*5oG6sAvaviA9!?dCL{o$ih$#RWl!Sd7Bj)ls2ej_!IsvPF-?a|BIFxQNaK6GC z0;l5xr`GG~`Vla!Yl|Kz31z^z8_%ve=t>96IY-W!X__ge@b2A13x&^g-N5m9hxZ-U zT4EG;Nu?C)x;AIk7s0u7KRuVr%76R+{tw1OkN2i&H4~`>LfCGvqh1qFPn%G52Zz$l zd?hNZerr0iuW$0@GfE;azkZG1-%=i5(IIbzlDFfnkEU7SUvE{PO9Igw)xZ(PaaS06bCPhkIv#K`j@l`V+*@0Vb@KC>@AGWl% zmm~W*TIVlx5dT(G$)A55^%wh{{F*=e#n9|m@6kUiwEeZ`|Ig7*f9X8@vyQ*jYyW2+ zyP3vc@RzT?{;e*c_E@ja`;F#UZdCajMX?BLKqMV+i>0-(FLEhuJ(T=UqaC%1X%YU>W;fYtoiF_|ALv4h zWvi{*)|eRVO*HlDyxfvHKbt<<{ojy4e*78T*GhY9E0)sS8FgDMs%(Nn0utI3VqDlZ z&$@1OzHi;4PEMA|pfXxZ1`^fL)eh?vr@I6F*fC8r^Sls3p=RmAPQC)@f#$W~_zYdj@|8r;fv5={v*q`HAWISuQ}MZWFQA8fUF&J}w{W`^@2J zDRo1&&!?gi!^Si{vrJb?j+mAebv%rG`0$S2cdcS$h^0rH4)1--Zi^_bxW9XcHBN$j zYs5LpILkFjc3El}YlX(kmd&&GBPAD}pD%3diqVR7^=#`Er4{eqy~A0{)AKW2uVQFX zIaSqY>hjLYUNV?#)hNZ|o^mD>i4*K9yWiMuRS_ z+e$7;7QxnlD;Z+QLI;Zlt!J^_)*bbo=WsB@n8-z{%+~eT&Y(@@tFPWO9tM8@`#*3! z&%`wo*MusX&UiXE;N8gOvhn->^&Qjo%5@sCwqRYM9~|#LJP7^9*e2M|80|3Hve|%h zqM=#W)ZV}-fy^Cf(=!|#?>-!O|J9LYy7Fo4A#bcP;+^I&_CV%xe!_c;YqsH9Y5LA_ zIvr42ak)IRuCvh8j7HYK^3ttAoF8c@o^~v8TjfJW##oE@8i-uZpXg%7=p)7`C;?|Q z5BELeXwXXR+7JDS&i0h3iLtVVh0FEKx^8S?d!e3D8HS#5>^Yqd)MJnHis$nqF|OR* zkKEsnSf?l@whmy&@u=}mG(KU=#8@fW;QffIne+O@)6<1*jr%7_HYiPSnImj#11Y&M zFVZ<%V<4tXteK<@#yH0DNS_jR+vxj_(`h8iLXK>D7G@PF<{I7repZxI;e_)v>pwf38 zr^Cqo>B#-vJww+Mv*WsGDnji#cW0JG!2GFc*JOe!&AdU(PqZ~cF>V6plIBS(u;5ltk;3n^Zq z2Kr8;NW#}upq*k3k?XuLuYqZebp4UT>7Eb^^P0twBPZ51a#1s`KXL^6z6Y;}ogq8J z`Z!`*97Bu?&Rf3u<|}&NadlVDpFVNkHVJ-DE80}Xp~rL%(|ID5bzNAOjdflmG<#j8 z``>l!EQ1gN-+%u-y6M@JuB2?~2Se9)IP1t+^4sQlWu6yOOs^ITF$ju&qr`yGwq?Uf zkwz&+PK6u`xn5YefcKtUJr@%L%+OUrTuFJQ>%sZT z*0gGXP;P;BS?T&7-w7Kcgw~CWkr*m5RJI7~R{8Yw#ATW>Mzd^Nqq8b(l{n@Yh3c)8 zxpmo=S%B^H^D`xv7AGL!Ze3SOd1~6|rVR{%bzMbg`>Og0Qq-B|RRDwrYYp?d()XUe z_b6S7EqAi-d#vrSPE%DPmzCVu9^M+rZ%s%3V+?@>Zwsw*4GQGbgbZ_tJY5zJdV4jlD1=arT_z1PuR-)_fQYNM)GiC(D{)5r?C zwm|Ni{=9=?ciEfR`P^0wOX9l!r4@! zBSC zU{uexR-Vh$v?D9l61O9`5Bu7x2EL?*?d{9?{Cl<4JykpyIB#obGy31Et5K zXB<4^*l`#;Y8Gc0%7{VXtj1aS+Iz_YLyI2HXeB(_ESW%^b5I?s8p*9wua{P-=Ezws zLts^Ty#Ya(8z}E{SQn z5VjTFHaP+e9R1)qoCe9ra*FSN7>IG@bQ-1OIf$OhIZM}h?(aro^y2;*g^m?drtgII zSIRTn8k?@_bqGIqr>V$EIuCw^D!}L8{N^Fha z9%CfObert0wYO?r&Y5l7ZWF!Iu&z=CbIwz;VVNT-MW(Aby2|AG(*21^re0Mu22IMD zZIce$&d*m$HA-Wm)`B*L%cT-xC6`F8g&e_Ij~LdBD&!8*QVV9^KcoA|xk!bx<#L)V*_JVj5sy+3<0kqnWX`Z& zmcu>E&N?N9sPGoB-74>`>-Eo4XMaPDtVJyOl@$Esrkg#AtSYfo){r^R8^`O+=`wQ~ z2abKmp>uRbGjxvBd92Z3^vlX$BnD-lxW%zkRw$)^d`z`fboW31dpbjY8DGYi@gILk zQ|YHev)|tK473+HLdr#=UZCNEM%$(_i)i|r{Gx$|w;k!v0o!XpS5zwwR#2si!J+WY z-=d>7&6T}dSOpiUS|wmxi%|(yFp*M9=4h>WHI3c~=KJjy!}f|^zyEyudShYiRLcEJ z(>T{x8nz$j7eI_cKXJ~s>S=0EEct0QXL8kqEwh-Fl(INXcAkfa2b{NzL(ex~e?>oZ zeEQ*u=TBGC^2j!2ta4c8Br_}vjn6sZ-p3fRPAsR#apZV7alK4jE>ok;ZOsz25Q2o% zrj&8c(RCf;IPm`c9l!mTuXuibo zF_Ja41*m~_y)e%+)GSVXzQ_AW%!!-}{o%mF`}aIOU%8w=q78JN$9s!0P;zA3X3kGf zeEaPm`SkI7)_JD$P_mOy@EDk<3)`{~vgf*aa*^xg`TWe~a%Npu&gUnfl5zt{3hwUi zdH?>m_^#*uyAND0S1y+;T5Gm#<>~1WVv!F&0v9S)u?3}|!W!-ogH{^|pVacrGg zgYp)qL6yWf9&xtA842fh*5b61&u!;;eEP)G2vM_ym7EoQ zf8a3QaqY*}?K2o7*MaXGr~4DJDood-(8OhM4)=DfP1wBqh`pzA#)XQ3swPCG<$7Bh`$UYX{FkSmAd0p~mBbta~GqjPMl1co|q zvDPuqky-*{f8eVR?lhdcUV;D7!84@}eJt!jC>Zsc2+ zD-pJpxNT_dF}fpWn3q5bp=?-;Bi z44yPZiq#lr(4|tFIG$3d4Y1X=rFiM<@v>2XH>{jn@a>z|@MU}%U&fcwMxzz}d9a4m zr>f}3c1!`|&r8 zY^^u&DL_q*qw=C}qcQ1jNh3WPt?HLP& zm}jQ>6SZ`dys$0{ih{EmWu%jJ=tsP_^qoalshFpfh^Y{wWebJQIo{phu_jApK`}!X z`%!B&)@X{61u<30&T`I57o|u*tg{1sXXrc2I9QGc4=Ccc5Y}gw>l52jai&sZp(agz z@GwZrIF}^ZbK?M1=2@(+#Z@k|hbX(&WpLi$v*CCg2|)mx7y+1DM{?Iz89kEA(z>fs zwbrdYeRKRXa!ysdS);JNWu>hv%eoTNg4-NEc&zWR#u4g9*b=IMZJZpX#I-Jj1zkJ} zFBDJ;oiiK{BejZSUkno=%%rrC;wqg`r?J{K;}1uv(Dx_C;huReP@kHJ)u0uWoG49? zxUMtLPmj#kDt?BQ zMorHm+@)e#x7V0T=M9I!vuzzH386opMvRprjJ1**)?0(2J)g2ztMS%iwMJFx8mXEg z1#(;=cNiS1R7xn4oz}XKF-J00x-(?95Xfq#>NDCM7`5gwp77m(N*1Exbh=|029ioQ zUFKep$ob`#w#;?9pz=VkMx5*Ex`A!;tGl(Mtf>C;v$P^OXqoEnwQ%K zeA^P+n&>*u&|6}HlmaPbP`ZhzrLvf6p;U8Q=w9FU*b1dI&N<0kYt&$=lByeh@>WHC z<>Iw3-Z#N`dv2v=xhja;YDuz~%k?1d)m8)AG$zC#xp1XQ@k*;oEq^XJ`=4pN)z94u zu1YcmRZ&grA@|BCQWl&4>viEW&Rh>YcY|kjhHcphy~kUP@si8-|KFXPMjJB+=<_3{gD5*9HiY27ueFh(5JMRO$JreJst*go(2zwX$*25hpfH~w3# zS*dnh8q#+HSiH<>j#@AJ(*E-jU}{Ycwr(VDGZ&S4B(Ja0t3d(v%htDBTKY z>P4;wzg$$bF~%Du=*1?ppp|S~ob55%aymTlU;jVTKM?sd$w&R1VhddZ3Nj*)0ue|5&y%(1D!iii{bIpGtZaI zH^2Q2){U?%C^R8PjDh?619z&U@BJ+nA*PjDMH?u_76$Koy3rHj%H!ilVw%Y%;6_Iu z2f9+)Cb-888s># zek2`6hHfNP2tkptZ4wEDun@u`bX6;z0j=f23}NB>AHL&yohenbZCi_aNViSvFbrs| z2w`PiHnuHN(G1hZ@hCJm=N!u#SXK#Gc1|J)hQo=kZAVO*QZ*q&!u649TG@h7R*jab zea?v-1IED6IeKr2$%x}o&1_+%1{em59eVcZqLiis#Ndn-9cBzH(}icfVl;g9;T@F3 zwrr3!y*omNFu@W6*KiSPZ7foJ@eXYag-VElX<0Zue9iCv_5Z-rK~!|zKtBv5oiP~7 zdL>;SIRB|{`n63=Ia1-%<41Hka_u%#Nf@ips?zrwqXN^ka(SMyszX;NpudQr3`(&~8!-gtIni}z zre&q?PhzN{G+R(ya=7vJOSWyH^MEI3T6UpClW1GDpT=jK#?U!EY-*@~q zq|Cn=q4PC;>VM<-M-ozh)o1*lWc;%p*8YL^sAReLJUfv zd7+7OH|<3td8|sQ)@4&SN;_}^Y4w(`QB~^-UC)yP%jmBjSB`Hc48qYKZQcOHPp1GVCu9x)&%t93F`Oa7RPPcAb zW|}6P(_H6_`Ju3F7nX3wV8xccXlgO!SV;k#aXg&v#R+m=pm+4$o(o3L4LF@XXWH?DkFTD2W@}r$^N`Ub|!F+B7B;+q$-{nT*a&GOmyK;*+18cum_-X^9M;1& zuWTVOHzz)`^tdq6=>g*3oJ_9#-)l&05{ijTx5 z7^7ulYC$!QbV>~|etM^tQK+S9*czoUgiT@_lH`olVo_Ld4y$OIyhJJX z#>J*&a)Pjld+DJ+GG8yu*9oI6R(HgZ2qANwXCCKALdwMUSr*G&xz2NrY}-n$1@An) z?J?d^fv_!PTd5|aTc_A)MX8w(H>UZ@Rub3i8LtgTQzV4F>)5=<+$a%+Tq0{&SYu&c zR#K?gM(x{guSd?Ad7gP)#1gk$xz>H>xU-(acwjtqIH$;YBP6+&m4@*!a6AmuoCxdI z-k-u2AVkpzYAv60>qUEuDo`~gtCodX&^U~SX<3-BSG*Z8+BYz?bN&=DWkM=kr$DLC zC}U98NzR})P^}a<%D!ky;Xx~p!cuF#X?$Z0cq2Jpz7>=d@}8BFZ(wYvu_%?%ssOvI zqAV@a=}$mx+QgUqwH<)$^l7aX+NeeiX;soH?p=H5M>Q{H!7Oc&qf(3}C(X8&mbD6y=p}O&V4Wz}DMy?i+>%WnLEP{lD9W<1gDbz1i@*LO=VF-9VF;kAqZbwOoDW z?Xjg&q{B8XJoldGvF9{)^j3;^-Qe-P$9U0m8f}CYsT9yUZb~)2P36U%p|9|iJd6@kA7=HTE-vai((fA7q5%U-{pV9@&6+`)PJ^W#9xjaUqANikKrqH_8OQ;j^`^-_7mq`7#8&fB+;Ck(E`|N z5ih@rART2vz39_E2WUU{v*hf8Y5{CYA!cr+wy&}ecpXKs1G~KoD6d7#N^-mJ3o31= zMX6@?w7Vfo(?k_@18l~q8@pr&v^#**ZJm38v+O~gxAShbHWC7>B`8~7>>`!noYC6w z?)`hd`s!;+72VBOUw^|_-+aw9UAbN_JU>6NZVRQz=2$CfK^AAhR zX%gB{&Kji$oHrOZ&{arfC5DChdTu(kObi8M4Q5Brr4qJHY`xPSyq8F6L+gyvnbTd* zSMRJQMwVeNH;-gP47E;FZ3p3G|IQ2;w6wnB&>lHBe{hePtz>4u`J?!-#G!5MR7S# z{M*0%0qbB5XHt%6B{^T-`CA1VG%;q*mn(nx!=G5!MQqKLVqG?-Y2|vB^Eez8R9S?eT3kWL#uN>a?bpF6rg+gYGqw9O_-#uWhA*Gear;ntRS=Wv6aN_>qE3_4N zMBhnH+VlBBh*#-AmBJb}wy@Iqp0B@NS(Y;&KNhanCyc3BE3~V9Qt*Ax{kwMYTl9_u>J=V#V+;e5W3a^n8(j;`;T`{#i_{pn9UJw8#ZA#5A#val^HDKx<5jR2v( z!+XaxpZU|bk;lsu(>9}QN3I6wQMzZD0_W!o$9|x9Ry2CshIfV-g|h3NW9U1MhYqbX zwM1elEK9&!z!_rBgcNyte&+Yz|3S_jT3jOM$S_uXHvkE8;OXP{{P$ex?LenH3WZb( zn2K_W_4>s0_yhBDrBIl+g>S$AmTEMmWc*+`+z;qnF={0)Jr{Iy+I0BifE@ndG%>oisiC=s6$BO+-E-OzJ5b}}Ev z)UL+Le7T{y32-fJ#Hv;BlrcZFX9wy zHKvM*Ss{PcC92S*39t8Z<@Wmbqket7?JwVG-hbU@_%F=>+mGh20S&daR_p#?KRG_L z*1nCu=SE!pitlCIl#YMlY53*W{ww}g{WNU;xi0NL>i0i2Udk{(9zO?#|2@Bdn`HQN z&;R!szow|L&rL5sz5eT8{{21!ye)CIT2ccpCGSN&Dbnq8U9K(qRx4C_dz3qH0h#s$ z&}4DWRvB&cF7!fGBNWD5$oqdPi@BL9Vx&Z+C@~q)7>bg0JSo}V3SfJElem_bdFLg2 za|e=A@KY!nKB|(BS=$TTU&HHFL_pY!Nr^Rb>6qF&Y|RtOnl{~6Db()l4~4!N&8t^M zL~E_XG-{Cd{zlu1u~kN?Vwdb4^D=S1cz*NS-*9(#;&2!l4<^a94R?A;lG3; zOL%NW>B7+WczeV&aGGM_e4a4M(|N_UF2oJ2wrFMO`btRRk|!4F5#u7IN^aEk^2GC} zPh8Izwk4256`Ey{<26?3rBp>u8Lc$ldSX??W;Bs=mDiIc95zJx5TsnFXng0X*|2Vr zrO`htiI`?;O&DY8x}MYNM5!+haVcf4*O~9W{eciRzWV9|!!QtIW?43#pC;BVg1N&F zmTlAMSu*#ilF4PQl91ZC$^zRmrmb-(V`Kx{bbeJ=wAFM&$8bEbY?Ew&QWdwhl+jtb zQrbdQiLGqJ+`2fiqN0MVDaEu+vcXt~?|ZZrdg{~j5BScbsyO`h{eg$~UrR9n$xt)a zGR-Tw7IGCWO-g}fo>-PE+ct5z!aSY1Ts{H`)haf72hBK->jr8{w`?l!Ws{ClV(@T0 zP-?;$MT&uvBN0RtTg9!@Sw}^qwb1oSL0kcICWM5lB2u-=;+)2JLMz5-rs=}@^32oI z6R9MeGu)-qEx>UP8+W#&q)ggYa*Whm&?ubobgmayQe9crE6aN2`FdsAHni!<)k>z9 z8_{~hnVCEu*t}z&C$<;~F%eQCl?G_hP&GLvVime$OjSZADTEwZ`7B-hsvzXV^ZAVNj;s~RR7|hw zibltQ)%92mRU7)=(G3R#edbaRtzfr__k zVXfedBY(%(g|0HaPEY7-R=)r5b!Oq+H3( z`OCCuic$-?i0de5jIyHVssf!SdF;2SKYFn1CHv)cqc4L?h8)BSlqW zt*kk7T{oWQmEpQF3I8I{93^FkLhv!n)Cm2|Mrji{m+em8gH^=aE5B6sYDtvzB?8PquXQKUTEQ#B!`}Tb8_rG=H8i*4=4Sh52 zsuZd!t-U3BUWIvi4Lgmp{ih8S-P|2jL8~IP$6Anw5#S@4t8anZ&H&N6QmZECSKYd1 zK0t`=QsH`!Nc4MijDtoDbBmvtgl0c=|D4~V?x*6OQDVaH*-Z8WSE zeZw$-wOKl9De!#$M5QuZK5@A|63fE7`CW5S%lOW6|8U}b-gCO-q}E(XHM8YFNiX!l zoD-!av=J4afDKrdnfx(vJPjNV0sYz3^Cg(^lNi3(WZqK2_B%}3C6_uJZDM(kq zXwNpor|*~68qIwC;lky-;jN-%M~Z>Xh~`2o3uZ$ZvFt86(shYxj*R1x@o+?w+2)CD zUI=R@Y(h;-N#4YqGt07)q5#;#;lSy16mx;vK0rXtis>5gou?a)R5mV`M`}ro2aUoI z%SsNBl#o#0b)%Go_XVn<>mt@@hJGOD%=P-rJZ)l$Ulo0KMC%T4csGcnVk#_4Mx7J= zv7e+D;+A(Dc>n$$g>=Qo&5iS1y+)Vp_S*&un2v*9^I0YQ`xVnDz|)$S{mRVciy-lWT2D zq9mP#Ta#}ah6My9rKOQ>kZw>UM^8qK2I=lj=?3YN?v5dibTkI=K%~F-cYOZ< z$2hh7>=KmXG#&&7+&0bBNvq-@lyL~k*`T0+i1_5^T!{IPc$TP}4 ziL@1M90Pq(-Xzs^xfil=AGCzOYgSs)S8yWuiFN)w%587Q_&V2R{iW#W>aun@V+VA> zzAWK*2e@ncbGHg@_^wtlvw8yjKC|DhaVI`|4C&*Ew;aTXIdCB$Zex`jzw^?F`ak@g zwjE}RKo$g%SCYu;MY}Q|yanN`!y3`I`}2CWUM8d~oA8hG)6q)11P2e~pdeU%#EHS? zY{nNfx!+^>>OGT4gjnGudWUX%eWO`9$B_#5lbv#%PL}#;22*-x^Ke2?8Ku9$SAl7p z$!M0hREusmB(d==_-9<~&)tBVXDMo>;FcaR1hhPs7{}j$4-FeBR}p+7Ph-u&^5dxWbwmIMCX`6x z2}*)URWc|mZ!c%`#AI)P;dim@V8m5-J_LFD1x1(z2l%T!bVwaq7uNUQR@n|~_t0qh z|IRo5he~GrfxvsAG^kC!QX52yIc>Wss)1u6<07u0uJWVv`3Uz;yIddht$Ojt=fu5p zZ|vQbOUABKZ$^_6cY;U%d82jo`JCN#KHaFiyaa+7HGen0$Xw5E9#s_V)1fRseoE-G zCca#eeww8j5+i5~|VvD`^k`-dQQR*2+Z15Tb)$;>r z&|MaO{Iux!aM2g#9{K>Q$u& zoSbu}cR^ntcAQ)t>pp94S@nE%61XzVvKnnQjPc#OxsRUTCGe7@ZPMvv#Qn;mC-*xaVyXcFL&#N~I zgs^PK{0KNXKRelYrTw>H22cQVy?0C=6YaYTI1`q!G$v^o^`4I`Rn&sD+xRp$_Xn&} z>hN0%A_P&T(1+&znPCF0En#n(DD8Hf4_nWs&)@7lgm@>qHr84&ykeWsiXFTmHhSuB zmL}c}^Tsxj-z%>BrvFJR)`6&WE$mC1UX}=}a?D^231qxXxI#8zk*q?`Ui?b&(IJ?rqlPRvSu_He&@VVyth zt5}taZj(3cugJc;^p%@@hlZN#3t8C)UWtHq63l91 z3Q5*k-VL$i2NZzqfYKF4AN!0Os-40H6GBLel zLUT@~+LA;5pcj66TemZ$wcFfyw{b?9P)Xh`CFngU#na&2o)t&YKr?nGEyv)sb>aTh zrq8HZvf)scz^{ANiBO{_HgQcrqU%ZX{g+v2nM%bsiNQJl4BsB9dHmIQ7`f%#glR&>ncuBbA@Br?7rune)Rx-1 zPjh;c$=nyxMitofTm0)1oI*eJz|-D!v5h95?wze2&vVji&zH_LKna@=NrJ!|v74(i zEfr+9E6V!ddTT|&g*>mRQ`~%Y_u&8c%CiBZ#)$tfMqy7-?U&mJMDUY;(z+M>s|;?J zd={Q9SFr@c`o#Cn6pCg^m&S|N_-Wq+S!Z%3_Ipz}+O(o=4mSIOg8$#A%sl^GvamsJ zIjem^t6b*nF~kDt)gt@8lBr`;H!zrruWgIIZ4e(X`u0>kxsAi4DvcxbeFIvXjL6V! z6|RWUUmio-OW$u?mb|xZo~Kv8O$c#cCuOoj+eK>?)@yTOGajOeI&Y0JX0@@7WG-h z-p#y^tYea$e$Jl~FKam90r}}bF%mlHy1%pYAFCU9emBUv`Lm1}dEO2rPtI;0@8Yjz z8RJ};Gp&-%_i5lDVWSzp{$%hs;e=_}$AT}fKw2J;aw}IJL8b+|K%*g0#!XTW=C~(r zlq3Ct$n$#=Q7s{Ni!8#G`h;G33uY8DUhbwek}gvGaAp8!L~ zL(JZ0sBLzKA&+5$00KrJyX)7{=twv&m^y*hihT(qTyvd54#AWw-B&z^$n{ndkT~cBKs{)ya{tAt4{>y@{uFyfVebK+vXGx-*G|?n-#O=Da65A!|JEB{gKFfP% zK==q)Gyc1*y7+fYymAamOzAxy%xiPw$$TxyRM$B3=a0+o&Vv--O19OJl)|R*B=-|@ zHUsWT1qHOq?C1XxyK&e#BR|=^*QfxLn~{$CK7z4Vemw`iKF$;`(awOGS7#y#Dx6$8 zz-LzU(jzbm^-viXK-@%FcBWp1aim-3vkM6bV}iA<)-!VDZ=0vgYhS&&nc4j*5>U6BIUcvy@!^;u@J zZrJuA|fHQW3B z7xKsubBpQqlMd&%d@+H2e36UC;oz1z28&Mggd;;HQzM**E4+T&GlLm$KuT;;?{J@o zQ53-0mdHco@;DB!#tQR)fm%m5H9DdG%gYRSdki~-n<wCJFTv|W-HM?QF?flfG3$ZfZKJtt@Ie2tVyiRYl@Fx7groAlU+F6U1?TKS}6afr9 zJBEd*lk!7^8Ysl$7HEt)tI}#7ik53eo%`&c{P)!Uil938RciQOIhz!t|F_+jS^f9j z_uMn84vZ}_u|GXmL*er~QoC7UuG3!40>&t6e29qxkzn&bj_>ImN1{v=R@yOOPe?~ zneE$Qn&6_Akb)l$ug*q!kv`giZ!J-DCim_SJC>uXK7SzVAzr&-c{l$oC)D7V-ndwE zJr07OPvcb@*sua;QP54)5XE(2T?=SP^O{z+EqErnQvb}YF|jjx-O(V*dzd$`065vj zHuHb_DRRX0p6TnN$RN4YlbY#mQL6FA`fR@+8o7VSu^o$(m=T=4%)~JXd?1|xh!t94 zxpmgvG8cbN$2JE;cQBK>?65$8bvRBy^Vd>v8@O-AY?RZNbcHszncd$i{~GzA&mzI$ zUzHPelpWS51U0x2Q)I%LyDq+xv_3xGigLusN|B!VdMokeK=U+s_wEd^$KGacU+g^e zxp|BHaq*Vbe~(K%DJd}f%1$2FxYddpzY>uB*{3IhWPB1w6Rk_u9&nJ7C6I%UFMZD5 zzy(Eyn4pApq45a8Ui+KZ+|JVy8ZwvB66IfAW{~LwWQV@x@MjYifyEhNZ5d|d6yh3K zRO+N-C~DvQ-*5XTjuIlIX4TpHUS3y_?QgNv#H!* z?HGK!b=1ku!l@8g2rf@kGpaBEr^pn4#uAu z-PE<{u=x5Gs8cEP70oRbM>oaJt3$X$d!V8oO?&g;R9J17G5jy zEY=z4TZB%%d)u$7DnPF;YT}~4)3dWTI^-edF1e`%I&kyd^$Q%ip*`{!H_{qubJsE` z8prx6%a#htRe0xR)05m{qsGjyR??c@-D&mHtd$&nC9r8i-cUG!uuk_y+SVpnH~1|; z>Ii_D#&>JXMQs2< zFKTmYw7N zROXqpAe|R!cABJROr1>c=G*O{&!g+?pD(WDk6a}pbw`nI4l*nvCn0J95^dBf{)Bui zhd^$@&GJuTk@tqt@Y~Akj3Re()_hgw$+6tT61$>?KiG|%a#6uEpdDVS;Fye)|5LGM z&Tp2xXUm+O8XSoyPUlV&av@qP7aLal-U;b*4tS(v}6+>U`%d36q$_uDmMTS#psr5-N}g58Qa+gO7B?Pvttr@3zZxmqz1 z(0EmT90rdxBOex*BCR5S$=EsX3*#yYKV*Tf5Icby!O=Ej!_Leis!VVpU31;LNw?(fW3>LG)8~J&O`7(6yc!$VE zzkIpbqkHV{WZ7b?)>qgl8YMnze~8tF5pWkrq>oK9XG;*nOj% z?z(Inc_hg7jg!;|Q()o5iFaNKggTEJZ*M&I(I7%^U&pmpHTaxtN z%D)xfbURsANU3RmvmYBUa_f|af6(lf&lBKxpOK8ZCF0$yCQdk_C->~48RdIJ859>i znm)FKG4c+WByx`~j?J;#>5aQGX3Ev2K#5=XHzFg!xbV4w8L2ky7}l)WDdI}-zQCar zh#kBIG!M3@Io-WPdExi@XLI$Vo{VQ(QZC+4Z`Yn{en~{zd(+GvY6(5hH$=`D1ROQx z%S$923A>ha%x8zyQI=17wp%a`cdy2Rl107Qx( z0Nk89YrIY^V#2bcv2K03M~AJi)3cH|b27p;fN5&hC$K*!RyaKi&3=Pv%)pwhu`VYS zmtC7@F`Pfv)8O5=8#k7b=$6FqGm<6+PLc1l$AevGK1eie%wmDr04!c_d)itH`Ye(e zZ9PFpS`7$!73$iFwOd)1%d;o`VJIr|#nN@5e6#QPIzB5g4Yh6TDrEs@Sq@GX(S&_QGdSlCEMIy(#qvFWV*Jg| z+#L&&s#~A9xrujOF!P>SyyD-swa7k_-|)_r?kojWp1%?y2C5D{UQPjvzIPo7V;UPr znWxtuo*q}?bG+%LLl~APh)`!&V(Q%i#?6By2yR_*o-c2Zus~@o1r=gj6Xs~B*;^VY zXuJM@()e72qT$e>I&1Yrr0DKxiLS?{M60lsh}(Hn!qwl)1MS@bv-e5FY315%wK7@t z95EH?1#)-y5n^4$*IOiSC*Qj{LDjE=yU(!Du(a!>opBF0tdT?ceN;qYRfXLt_@SzJ zYwG;-$yaj^xW6g&DH2UsnOoFdSTMg@b z>G+_;vJ8<-Jo2ddMr+Hf=z|)8C_kB*VorWn=;mJjuwN4mFJ!0Il3YA-G^LVM8DePN z1fADUSk9TeN^uVM+4Yfhlf)Y$;+qMH)MiS%=FbOeb!gjx_xL4Oaaf`7(yxWp`^&>$ zQwL;mr4~JR_bLP?iB{nu)#<$m@>?_u-g0Im5zRPl>5PK`&jS6-bOKcNIHwc^;x$j5 z5u5Io3kuax+ulF_?xhS~h_0aI03=~g-fz(jY?8&_`AsEl;)EkD^)(Om#Ro=1x2Q&( zTz(3*8yo+T*Nr(s{+)b1%PkM~ z_K0Nyp16%<-oz`y)GC|HbcT$Y2|g6*#1JYotBiGp^&;Nr5Px8Bit${lEEB#h@5pBG zJ;S1J;syYIgex&?`nAH~LZuWTdAl^HAm-2JI8feLKqakj@z!>@8H6bz#;2sLg$uo{ z9~F8}U_otk^pRgZ2227K>qfkja6QE(?g#-#=HaYwVI>eE@}|%pmEwzys77gzq^7_r z2JWUtpKMlP(eoMA%%}_wDQV#{PrGvLH0;YW33IC0ous&4jXE`Riz;LZ;P{vvV&;a@ z7a*~CuixgsN1}))ev!R!wOA)Bp#Aa>_=s(JQ{yWZ<@jgsM{5#2&XrI| z_54pod`x!PvA*Mx)MqD5sqe&nV-XPXUAP!DqYQv$_fXJau+$-S;$!ytiR&3HC>H_jEqh$R=0+ zT5ehi%%)$N$l%YkG|Q6UK@M0NlZ&fti`@n}y0;Hr4&=b^b^GPS?Y|5C(^O^iGc z>Xtt2yQ>WDA)T=PHB6Tfj3IugVWso!mC=sO&A(y$A7=r+_ZL^!e$sa;Uw#|~J=j+! z%LG-f{cROH5^e~39IJDwG%he~`}^50q8jR*X=L_Ri7V;8H*GV=B+abLU>`5J2i4+B zZsPsNasxt(j?Bc(M{hiPn>X?*-64M2im|eS0}aO8y*ibuaWK0E%|7xE$Jo`UW*h!_ zYQyDeTX}{@h9wuCdaR%QZK(3dOB|fsI%$^Fc=By4xw%}}eEqrU< z-DfSTOGy(p&&xiFhjT)FWnra~pAyLpT=T#AE3RDqcaF>@73V^Ai{`oGG(C1F5hz7$ z!+KgQ^SWsD5G6VN|ivn8*pD>6*QA6@U-%D-}mz@(PK2F6&(ax-3tY78x-^E(#uFL7P^Vn z*ZZwa!|B|$<{WOp4mTt@Grrv|dH7NY*B_@Ia-q*{WTZau=ixKz7{r5z8vmTM_Z_{V z7Nb7>)9Z{uB-M+^F1LRCR}s9oSmEp&@R;b^`NOcpL!49RUR~S@(fNkA7;B33@P?x7 zTJ2y91zyTjxTU{x`K41H?BTIVvv*8eCN;@2LYIliCb!1VKXUr*<1LbGcyLGeIOdtt zZ>xTNE&Gbfe`fZJUS_t>Pi5m4$579X)CG*_4;J+io^co7XNz3>NI~B*rf$hTawTTA z4FFZDBZPoh-4b=~-3~fLkeS^r<}M9XWiCUv$U;bluC`8zaL-zU zeYc0A^B&KV3#=DPO-jtw6leRX^Ns~yzt95RriwHC%fV;zVN=UBA&5<(aVV#8YscG( zC0uqKausH?I!t?ZXz0REvQL0=wwUhv1xgHMvWr<@3CCE6gV)otX`>!OQ(@1@(e+uj zukpLd4w@)`O*D3^!#o$DeFI$0Eb=QjIQFG+%GAf!HeudqQ9WJ_H*MLz(x)aRgGo*KceVY+YT+AlEes_ z?aQ;-rHiRnWxirIYM^PX%5|{yj=L9o3wv^^Fc`p}Dt%iWE9%CXQ(t?0WM^AgE7k6l zO24d>iTd|rFe=!vD?OoFDb_xh+=;^TuCv#EHSO6zZT~5>R!WaFJdC+;B3Xq#Ji*dv ztNV?;8X8XXJn2#YM)fZ5yCN}G6e+f)*ZS6=P+=lDLlDcW`Ow;Rj0w#&mX8shrbgey zHKEl@3I;&2O??z|muwZ*f91F1*Av|sl>hzYt_=l2!WX)U-K$Hjps^wnXV2TJXiqxf zv9V3(>+{u_rd}>Sl-ohCM3feg`>y|N!`B0)GQ&y7DN^gh1ERf3$gqCdhxu%_5_*b= zHOB9SAh_tc^{n}HgbGgM@L)f~_Two_V)&ZsIors(uP=L?^WOo3npO)O*?EUtmXIt) zG1kO<3sDa)TShK{H7Mv^?ZOJg@E<6tr8ogd;#E6PC(Pr;i)S1F&+ixNfy4QWr36)C zDJn@|QiLE)foHxxEIW07KwXSzccc?b6kP5m>XC|7$*k)4(|=&C<;qyv0wVr=vfK2& z|NPBvPQ6o(RsD)}6RU1|<20M4D7Ctt|18Yd$M3#?PC5wS#Jp5Rl9u@%dq7=lC)u0p za1fmYiwY=*2k|f>aD4*#u_&Sm-p2D=UEY549pdL*D8O*{03F#crgNv&@-gA(4|JfB z48ypAfM=LcT8{724$Ta^+nQcxj3Z5xP7@anGJv_P&GE;FyV?oQ=hN6Q3Utr>inF_N zZc=fZi5T1LXy3t~Vaucz{2+O82~$WExGcTN%kCYC+6pwMURxZlF*_?M6}Zc9lvQut z4dn6#c!8Zajsi~dbXBT3b2-=L0U1Ioc0c(Y%b}9Zcjq(O!s|~{?4V5+!)#R(amOt^ zkI)=<|3o>Zlv4h3S1hk)&gjM8^VF{ICy7eU^LvaM04z2abJL&deJg237H%C0eI?C( zL;V#c2!(wil|t*O9vr9Y|r1nuKqb>5Evs9+izv2Gb9_Ay(6?t013MKCbtB zX8>WneD``SzUew8`gdzPR&R+cy15s`RM6d4$ZM=eGc+e3;iK8H=zoT}7w8T^o(l{8|BoZ<7L+1udrNGVG4px+tB z2d@g2#V(cy9aBF_3EG=P#(zQlcu+*?{jbVhqBU%|rK4Y7vbXJQ8S? z%nM<=Ifj+eUykXvMyx02jl8eVul@q~eK42BO&{LdC{H7lH(H--p6edv zIYDzavE5C=uNNz!(uwu4+5*ffYz|wf2*H+roN!T?Ku4Q(T`Zd~om$%o zgo}Kxq_$MXJZ6*y{bm}Mp9%F;_wK{=8`?q9&m%FltERbr%&|42{#nMCWB)f}22rff zKC*gGH?ZI^TZY}oL$%^d6gY7e_Hc=|H^&!`kC2)nzpX#=5p|2nX19vxHzm~(6JOuE zMG;9%mGKbepA}fyTNS>HO%sN5{|I1t^$E;519=Sq`4&AabLz?Qs>`NvlwQ4MsE^dN zH{Yz6WpAam5WoFzhT;$SuRhrCxZMnS204XvAN;A~JXmBL@hlvUE`!S+36AbXBe+(M zrviL|*vwFCGnek~Wz$;Kut^U~qsOP;54N8f6*J24q&ssco|!NxS?PE|G_Kbf7X_Z4 zqAo{MC@5^RkE?^+87X?7!H&i0>T^&|<6mbRczTkhqeeN(nSpQY$9lw`*| z^mRh{En7$B2&*dnRTo{DL)erRqvBkmJ^G=xv{T7k-m>$Xo1|Z&x0E+f{B+RJcomdzUo+T;I)# zp>O1w#9x4sI@L^KMUNG_PmX@bF=M8VIy^gm(&(W%PyCn)R<=m>2-T=d?J5nl?%fZY$1OXXzZqMcE{mf zN<9(I?O|*t)r}7Zg`|(`)V~yyrg;lbGS8g@f2-U45;uA1#;m)LC#GiK*Ul}QiPYah zg+;D9Nk3GaC0(DeufyanYndya*=?@KC9FXh?NvC)m=D(>?K+x0=atwI_9! zO9I=&w8~JpZ7Wj$Hpdo$YBeXQ&Q^d@IhB{ZBc{C2oKE!%)9)L%)WXj)Qs;ga7AJf> zH^-ghkOkm|xW3=-HigR?MX*^RVNE2A%(~i<%YL<2OWNl%g09JGq4q`9vel4(;vKuq ztOxkp6yq0Q{R~oP{2w$kO6iQa=1}eeX;NaGk&gitfASU9Lxhb4thsHdsz7{slGjOe zK7l>SGCi-Qjfj!_Er1~m1FXJEHm7G#9$5gz8Juh39!1S#am$ERhzDOS*6}lksM&l( zbb@|};%)#@ts<{8t@1)DmqMc-Gis&UdYS!>4ezQLtYpiSCp07yJc*?U|8T24f;fx5 z3WHK#_`e9LmeVBqSD`Im-Ba4*>)w?NC$G{9L)0Tnz3|9O=Hb7kShpnd+J-!>@^W_f z#Le?ZplZ>(HLwxL65}AS_7SZik4*`|Mybh1s;kpSztVbD^b5hslP(#X*N5;H96Ed zlV<|?Fk@&SbEvA$DHiq6xhARlkuo)?A|WTa#iwdGRT)wwXv4XDuruc>>JwQ~;Vq?p z?UBF!uxM8oPM&p`GU>D9=KEhM^5{t8&Jb!>l)+Uf4AOL}V-A;%cXK{u>iNPBF+?-& z_?Xh^Xev;yq*`*>$sJR4cH9+oCc#zqIp~A63zY94N(q-3N%`bdb8T^Qr4WSip$US! z1Q>8|AAkJmk*8o@xfjk93MLW$QDdt%V-BsQG_CnaB8#^K!Fu3TT%gp#)(SXzJ!%ck z8I$L@0KHPCwR}O3JifCwHdaWikO0KXP$44`7s=SDo#tAuI3IQnW{7EtBQdfPm~aQT z_EsS7>q*w{5|_PYWz=>R%OREmze$6q$ApBt(`7OoOlM?u)#SNI>@3^ER`203@#Q+x zWtgecgH7{E&Cjv)qWSt<_~2_=S4+$)Gg8Y5PknEptwxqZ-!eK>1%J25HX240n3|S$ zjPvfvSlRFDs7^SX&IR2Hbq1=W+2BW8W=wYxu<4K9P^d;Z>1^VCw}sbua=0c^_}e`s zAs4;t@y8A47+E1C_leno8P3eYgPfWicK^BW`r99%%b5KXtwnKU`o=h_(#GK+AYk+2 zRCwt-|IGT;MMrPjx^b7u2=89zxwo+J0J-DLn)!U7v_q1&;Gknr_pO_8I(@^hmzXdRw#wJ$T z_Fv!s<_rJOi6!^JF(qyyw%~y2fE`2XNW0zYbiEYrB&$BBDdc~|bcEP9FRV_#a-ag2 z$4fYB*%l#DR2RpZr`XD_rHPJ@l>GaXo0V=~$#rNgX%5LKEXSe*oVhAAA3;UzqCg}J zYfQ8ZkK=}__)!k!ux8C@vNlre{l`7S=3%MpX&ylVhE^bd0 z)cY<>s?4$QOm1@qsuG)0hV@-j1t-z{!?XMt`Vx;JZ}e?CQEGf@bwx0?o>8L?T9xmp zW#qTdAdTplV>iMpMeZ$|HXt7)J-)Al(~*zxG-89aMzsppv06^*jLThJTuce7aZQ3$ zu~z8ByfAA;zRtKv+I4Q7_T<6Y{mzFaH8v;shI@P~Z=Ym^uf zZ_1=ELwGm<(0XS5P2 z@1HTB-}4uzAL(x2W8OXjw$YTsm^`AuvzyWFd%A#!s~F@>a5K*=xqTHI@O_kQV8exr z8qYG?iwY!$?z!#=ZV3E)_w(n--bOs10K1WrmNsL)H#sBD#2aez$ajg1FZw}PXVghA zU-G{iZC&xKZ4}bx%M$JojsY zp__l-)JvlkS5e#{j9ZKNuH?nsSlI~Z^LSANUmNV|{cWI1q-TtzOwYyTG0=<^GvSF} zjPNZmK>AI_Zh85%Xpy3KBT!*Zfu<|Z_N81pu@eNJjkJlJthF@VoH&>>wqMeQ}o6E zci5c#yIF4QoUM^iU)7GET<`sjSdB)Q(8^>`t*t6Z{Ft26T;o|cxvKl2{9)p_;9Lc2J~GUY{TRBnEQOL^$j+v$-DM|b9Q1@kbcfjtIrEM4{R*AX~Rdh|Hp$p6IM*rwbZ|bD$pJz{F z%`AyC3)dM@qyD{*3b&a&?z4!+0hNMr_RlJ^xf62|91PJ#>CCK@Moz`0Az*U{>jX2S z;a4XvqJNfk>G%}fI}HCi{O!azv}Iu#$97(NeSEGY^5E!qO~b!7=PA`gO1T4+Ys%hk zUriy`(gd!IX>yOy({@i!qh;NtO>(l7n4V9%5NP36J-4N$I}@YD?0tCjKV&z}m!&$# zowVQi<1%!mUg-^BswVaef2wKx&DU&nv;A=?fp0WBhxf1ky+IU^h}dbwOcuj-RIjH} zti#t9khoTmQS{f&0%#*E$C>homw223e(DwuEk|H zgWa*_yh&+2Kasx8{C;IT2X~?X2x9x*GYL3Hp{U#*ZU^;wpPT12#X?ttY2&v2idB`ONhPA$nqyD@$tuT zXKXvSd)hFG8*+8msyV+R`@;4R=#~ToIT9CZhPFR54D+iJCFfp1@{tVW@R1eGSCvbD zf2>dcrXA&-0M{kapZv%=`Zd{{De{?T&BwSSBWG@QUGp)n$q7*nz`7Ja;;XT8O|9Xb zM@y?U-}GzBCtH*^rL{KP^1IXss46Y*4Rq04mN#!CrLk7q;!Xb#2{AHcG#qP@3*(Tv zQAo^S9a&@Yzz9e|dJmJfS$JLzyNGJqF#{l}c;o`dd}Jewu?cT@a*X|eBvkyQX~Yx* z2lDZX)EXR*YM0MSHLerOV7F~Up?_MF=Q^`^{V7_m&b7fX=Gg?x3jwqE+81K6Ii;}9 zt8pg|D8B|)Qu3xi1DxYAl3PskR~rZh@ok^zLhdU1KDqEd3?ruCuR12#w}qjcUOy`B zx)LEpY(=?K$cavja$B<;)^b~hHeYr7K^S~kM}GqiCns46&9Thzxag#$LCV3o+RoFY zu|bwm23NcOa?F0&LFI++78oI)EPjYx_(6yd#W9x$CRATK4 zRnj@Rn~m|l+V@~fRl$#po#Ygs|2+QtxJIiMpmp5i-A%%7k&UV>w7uSZW4CZyijK?j zs~6wVVz5oP%u=@>ng30EeF?c=lrUxnI$J>7@`V#rk|stmf^2)APJ!Ij`zmt5Ej+!w zEjIQH05GamV~H1=R*Lcx8^UYK()n)QI}vJX#K^A9{(&=rKgSSt(r?76It6ob$AyV% z7%7Mpe>L*m>^_u-cJ7xh?n8s#sB`vgx+O=rCmB^p*7$L@?G#`-ipcrqL3@UoXW$B- z94NzqQwpz#Edt~c(PLfPFow3*-)uw3A&6|d-+E=0Bw+ld*F84&#E#DfkN-u(5+B)? zdiQql8*R#7y!+{GCBQF|WA>9>zWNi$w#cw7-aQezb9JCvMQDKy@~%BcH(_|7H}4to zo$K7KD+4zz_hWOR>+likbfoSL@ehjYx~UqDq-0@tv}iAWPG{WJgp{pHq=`obd)0~sf~TM@sjlvb9A&T_=nR!$md#}H?`WRWnAHc?F9o71jP30nnKz* z^NTAJh?{|K3}fShf0q{nlnfAw>L#XxXg$FU+q&-VT0>(7vsyQ`oLHJXO;k)?NUy>% ziB=Ry{*&R`_>Rd-}-Lls617C*v8hGmqaxh5IF z2;@MTK)!FkCkD+y))6kf6^|{w-Za00?eod>9AY6^qi;o`w?P$4l-x@rpopB(*gZ)^ zj^1GiJfr9=7i=2J@%)*+|l+UU#J_wJ6Tou0m#m9q~ z5dsIxzbWHWdB_*;%z+cN?z;ys8LP#kQ~xwV`Bw1{I0%a@IfkD1B590cMt_)wmm8`u zhfnEa)_UPyd+Y6GFUm=>qRiS3XT_f3&ai97FiW*8o!z(`iBTtgbeHWKLLwt9v2c6P z)R#D9rM~puC7$0z?6?#nX%LiHNLfQGH$cqlQ-eh>fJ>riGF-euZYUxECO1k6te z2y@1Mqir>CsSJ^`vgG%mu$W^Pf@@w@89{{07T5+j;omkNP)fMrc3`NFuhDo_G9}($ z7n>Cu^gXU1m#^Q;- zPK+#1Fos<3?q3CMReQ+%>p>T$QY>%snrGv)saya4xnRN)FCIBznFri|qvEW8az7M- zP=}Rg0X2}NaIAgJ%nAz-H!k(hz2$l4;_nbFiSu}*{pv|)kN10~$kFlaX7cTY^u0Fo z-v&?WC*6XiV3n1DzQ6yD{pR~lr2&dFX{g4Ew*^8E9oryMqN`L$$kAMj&*7= zA!_lpPsT-(nqo9N568QL*z{|+agG;dWwq}A2lP}Wdf(L`P1}X>j3VU1#uqG>qrnTDs{On zS$bc!l3qV5!-QsXFIf>`EcVZ$Gm7pb2i!%TXf1uuk)?QV%x($S;M<(h#RjPSWbsKX zEEG63eEfpw;SqY)sM$*N*6)?md9cdta;$f6(pQk#naHv$YyG)`Vrq275yDh+YU0T( zr53?1bAf7aT%%FfpFl7^WLnJQ14GraW+Py6)hj~k>yBGm`315Zp(-^LKaZ^TwSRFn z?;jyRYQ!j}%C*PI%yK*99(<3zjF(pYqDV6r=EGfA+@t`W0>`)|)GLfoD)JRBTk*bL zDG~{6d6jGr{4!SgX}_Olq>oNAqNMixV}6=16d}t*JRPnRb3mjC`QTo5h)ZEtyIMUr zBho~ywLMu)k-P%3CV780-jruf(KHpUVw+><^${+b_?A~5|hiLcPQ$Y73$1ezWAj;J@V7{R^e?O^PPAOaRoxG@C$ zfg*2k(MXGwpw2%rk`P=IAtGcJNu>la_DtH9%H59fa3A|)zc^3OZ%nTb;7}HJ=7Cn2 zn0HH#l8?P>uZ3vd9F#C4U8uXR(UIG@{l~F8%H(O07ggHEbG$D&Unjb*H+v6{Fl^cz z)?u!A#=ofA#_8}{*Qneh+DI~(`M6UiiNv^4f}qEW5m#iu!rFYKe1nTd5c28`rR7K3 zHT0>+4Ysp0hkKIB+m7{rO-E0y^Sf}c57t|9+?y$6nFE)1&wopSpzJ_Oegb<{oO@~$7D7$Cjgn~{(}CdF`e5q|JF!|7;9I+ zhsBJOw+82!ZZuoIb_H`2KMZI01{DiTjI$JMA754r?Nvla>n*X25RCDqe13;84#RxQ zuEGsU`%Sc8npH7$(9MsVSahZ-+P`Z!Y9<_YV%ZMjGk0;y&#T>8*A|_T#|y0ielQDW-~F7B2nsnWOYcONS-J zC}}Sn?sxw2L@swTNFcTAF8Mb>2P!Y$j4qZstZvBj%9!`d*wwFIp3nsdp3{eTL}z`v z!*Jn>c#k!YFf03xfwSP{!$Zi<9oW|f_QDH;EBWfCw|BD#!i9Bc^h*wP7P z5$VXw_en5}Gb!LIvZYcI9G^nXoLr0qLZOIBiZdGc_nvVNYQ=)VvHz5a&b>D|GjxBP zOrg?zGhhCwM7bC2%RkDF0p+LcA|1l; z&57p3>0jD~ma1XQ**p99j(0rm<>~E=aAu<9N=1!Ai2 zezW`H!RsY3Ev?d(ztCe2Qnw6jBir>_$kVejWm1Kns^96ILbI7vprWgO1F{VONcdu70J|`@f0i2ONbLMU%(N?-3VYD-_;%vWtBej)Plc6uS8Pjp zS*X_B70abo&L-|ptBpv7uJ8Y*T^*zLaP}t6YHww+YKk9!|GYj5tGi`vSZjWC9$hcg zI=TBdXzHdC6L9VxT#Ad#3>lVTjrmiN@I{*41mt&567pamX(Dr{dnFS1Sf@Xdi87)g z^VDbcqSkK3XY+8puGkCRvP`zuEO4y5O70)~WB}CegHC<1XVH?EbDLN*R@860?nUMX zDcduDpWq8}+qPNGc2Zc)M9&b;`fbHhx*a<=1Gle9#9HMtr1T>qxJze+($rqct&Ah( zxB*o=9RpH2P;N&k)>wW1-8`1TRvzs8%5of}+M%+nw-ewLr`%KRmEL^qZNm&Qo1J}C zd;Z^s!<%)wIeMcLNfR|lvq+NlBAkHTQvSpkoyv_nE$2lO5t=B@S9~LR3bktO*gO(; zjsYl;t82kt7PAxDuWnQbsGrM#Vvp{Hnmi3Q+|WJsJ%#dtNjJi>T>~r&cx%lLeeQDr z=iF06cW>|9jYi(A^~_O9o*=U$woL+B&5+!^hxmf8)@$lW6l-oIKl1i=LX@X8udHM1 z+QtzujcBnk|L8e7-$~hd4Z%8B`%nv=id7j0vi*I%7vjC(agUzM!toA*;8I|?e|oG& zDOihQL89DdVQ>NYE2BuL|AGPi)Npj}YDn~Cxi?Rxi$Ffsh-n0E!Mws=7wr*s)F8?xiNbq5tjUR@Gq&LtE}Vu2Yk>7Hh1Mbe9(Z{dTm`;#(voj* zy>TCCwu7;!5CXYNH|H)tcFyHy-V{X8c0fcp0k|u4rUT5N?37@8u}2FiaqX2c&d&3- zQ{v`r&;rlA3*9>zR!YfO;8kAik-Z>527J>TbIrIZGH#Ca3AtcK(`O0o}Z z&r+duM4eCk{oJxZnLVW1W6P}h`@8k>fzCS>b}V)Kx-NonuvNpzGW6WIH*V{>nbQ_4 z^NkV@Lp1RK7r@Ij&9TbxmFG+vL8Fb>CdOpr>&oOXFGGj}{c~yeAcx3;L=Z>2(`6%RV;>C*@aMv0$ z=&(6$q2T%V#93iwXR8_d@SgvXbk<=_{%;#51f`_AB&CrC1;GgjqeqVh>5}e}?gmNe z9^F#X(m4Tnz>aQPh%PFTx!M_^Vy-}2{`fnZF@ZnAc**-%4cqB_tv6`O?~?Gr;p_U;;?4JSFFc*o%!}XF zLHy@##%J?6S4|sNEF1S9hI5i`URD%7`cC&^X$4j9dvTZqUEO>oTwd9pmhf6N^uTm` z*tsoe5ps|S2Y2iIXuYoGa!vQBYTmJ^+=FV5cc6<3OipPBPg*5)tBe{nDn&$*L(-ck zn@3 zCa|rlfJ2J1_w5m>LfBn1{B8oQ-G|HyW~CpM`c2#7uB=A8YJK(t;kdX2@`X0k0kXAz zT{VugntHS)L5e;JBYwaK_Y8esc-St@PPhX=?VhJK6NM_&l;aPgam^FbLwz7xJeu;e zvtE}A=F}rHoVZbvk{=5n#1mblfF{uiP?~&5AY^2q_D#H`866ZaR@wDFV@@lS)VUNF zE6`JDXsiXWxxp({nu-gP2~QJ7Sl(~UdL+yr%4}TLyc^U8CFK(#v2Ui#;v{PpyB6A& zj5ON>|LEkW$66Ta=I7^sS{LAB>G-Ij)x71$+HGHj9?bi1(#GNtCU5T@=wp>T1zUl5 zollX3J3(WvOo!B8mHk1ldsax+h45@q(|BC?_Pek35d*|ywC^=ElXlt@59P`nSD50K zkOz;67gtD}0yoE9!PbJMq*PY4)~uJ5CvUm2GJJLugYH;*ZwHW6j&Q5 z@QL*{LeiGWsp2nNG|c@3tb1fDC*a^`$vyxz$AL7IuUFtXJm{`{Sp-k}nfz;0vcJpjd;rtH;iWxW(}xVixBtymAUK zveK43)~Yje1jKO7jWwXNj8E-gxnE5siL&&+f?y0L6%qw>nA&p82&mw28k#BsvZVOYP?*LUL>ZyQ*d_THS= z)vs&VZGJ;a1C?~aMuN^8izQjJy_icv7Bs{E>kSc6_QEIq0YK;Rfb3BJ(8c$C*G|Z`GZr?)SCp-o!;8`l!O*u#U;UphKglK6 zB0uT{6)QR69*XU)wv2U+w@?*_)R1*(Bg|u&VQ}yuPBXJI^HMj9vhuhcSDL6}aRe2v z1bD!QkKBT8T_R$$ukdmLCCf=YL-0&1P6LobTgF=zrc{WuGQ@?AwREqiHnE4r=+M94 z&!)^On1l*32@}4OIjl~c$F9mv?<<9mHd1hD+$}e2{j(F{*d?MqS>cE=tHW@3_t#3< zPn<#S5V;^k_nL3Mom;4O{PS!N_08)pL zzexP=>HXy(9#cZi_=LC-zzz=xDnRJOX%9A^`u6;OgYzl={MXvos7eyjs7Gu_i#i2N zv@>7sD|XisU19*9Y$9*c(n88;hvk+E3RjqXpJ!bHtSKI&5m(fPD`VHsU%}g+Pyyij z7p>ZG)T>0*YjcoBPM0yk?8xwpZ`zWgXd3p83=XkR;C^hIyr!#?4^EcWVsdkvzklrZ zH7fIrvx?HIRIR;^)Oa4wHZMac{lsC)0MKRkjU*=GM*_SCQ`-fF$^z?Q&cC;W!X`4k z$a%Ph*KSJN6O9hv8iy0$Tvd_&GjT*d+AtHOhigXel9Do+UqK{N#adM?Fx%0io#IG( z*fICmdK*-n0u*`G({0f$e?M#jhN5=dXKt`1UHcjBKg3-kX(a827;5~}hQs6Qda%o? z3bay`e#v3tNbyXr8@gjX%$y#?T(V$Opg;J2Zbi@oq`{2~iRLikWFxUCM3f{pq!4@P z6qb&)H2q!7JMK)c+H2XjzeL%`&NkMRNMf48oTXABv!b2N7C&3aYXK$JR*v&q^KO>i zesLA^H;p_cR@#MW>byq9`c6xs4Pf7Skg2hiMo65;(*sa6+4YWZQ?Gd@^H}zQJbyR! zx;`kOVo$_tvckC9xQ#2B7KWrKR@nO8sj!4#gjyco-1w4q8Gij16Zt0uycU(Xdf{y1 zhPtDWaX{^C}eQxDH~ zqOkj@#QG~jtsmnKB;!G=cI^ILnnnDcn=CW1UM=Wc>~UH3LB#alMEqe3c~9x^JIF%v zRF^tv_VO{B_R(4D=vexzX2@OThvLiKuBIrv09}E*cOvYh30;FRde=rX)A|G-^MKcoRB7~Xa+iDi)cC6#3UMTlD@6UcWCIrbIjZ9jGa3B ztx8+5xD5mpf>j-*7#NC&7!|o3KtH43-4)waYOzwKALaa-F$h=KySi9`QUiUr&c>P$ z2&uenb9&#%ZTv7>$O(ly@Mv4xS|CiK2`nxHZ&x>pj3Qm6_|>NG{RI8!DdlkGB6$%JY(%~-p5j)J1|Y4?C&Gvt%HGq)H>t9YS(xQhsGA{| zG{%ItojNMQhBKlxWKJRzz1;J5&pke7=?b7Z{5_G-=G&LMF*a1gg0uaRdfmuhMC0|E z{?k+{geh!Ua(K{&a!^?;Ohzb2CR`yZd3<-`MDP{AkiA|5*i2*s6;5UihT#tYPa#)l z_uNw+-W$Lo=Vos{zpI*~nT`ew& zzbtUn7eX<|#ILw>Sb7DwXme=Bh$B2v13vj!pY#dIYg|n6r+mQVV~br{aTyG)E_4lW zm)CjX46=ce`&?y*oW+yjhUDe*4YM``W#@7idHVobB>j>?W%CwzXIBOZ24s7X_s+?Q zOYcKl{@8NKS{pcBgt_%aOqG3cF<2Vjwh{R47R%GpW8N>`_Q-f>0`dtaICj99O{y{?JWra$~nSyD3FBSy;}~6kc1Su z1`i`rc5ZlmqkM;sHn~9<(7$=u4!TR!1L7dQTR^fdGc%JO-x(D=mjsr{8hhn_1_UtH z=q0Q=_;JOzHRS$?mR)}qYOOSVr^q~ksiK%1Cqh$7Fz_iY(3F2Yt`OUtH*Q=Roewoi z^S=1vH9T#{%Ta&^P8G#g=p5lLSs4qm`YPIv5WBom519@SAZlApI4j?i_SKF%zGcti)ain6Jf6B=?Iqe~SP>rs4c4 zYG3C=zevTcZ(M8eCGe_KZnxOKaf>#zYs9MWEI+U!}hNt*g-GvpmpALSE&xzSX0*P8u_Z|o5&Z+mo-*}g!+IAZKz zbQSQ}UP~w&8r*L?&pSvW?qcUji$Z$**!p9M&4bu42KVqLh@z6ucr%{OI2)!AXRBr% z{V+uwIbI0wJXhmJpvhTl3v(Fx!kDnigc6#?yEi=^K_y6EV-sT_RXy~DG@vf(1oVv3 z6*}ru#QI(@TMLC9CH$r@jiCS&#Y4U8lb9-It2f&b)kHrVUlgL}@*W zs)^zxk)b5<^tiXKS+zmo9G#9_Nfh=n#QM4?2V8Qh`CbgKUxKrs_|^lR>Nw)o-glq2 zyyiu;yomSjCnuRhhUA-8WvN%Q7YcJ#8}1O$Gdu+3pVRM8;-@#SPwu_c-0%C$#Q&h1$8l$l$40g1Qs(EsJ-P9< z(w|Zu*RQ2d(Q5Cagc>g?nHH8Fq5l1o*1dEm_$!k}AQd&4FUH6zpYiv|jOH zr##ktcKt-nc>nk~9+*0z{2QFbvrQAb4aGt(j_$bbQ-ew~boOOHJ&#F)0GVI6prDN^ zdrYJKLqC4Ke)qKH$vF@Wi4*Wfc-4`0WC#vZ-TY^3bPWnpi{hRa76q4Rbz8&$ zcB;-!U1#7&4-bK2=^KA3k-&K^q!uOaY#?pci=5WcHeAvsp@f6e>-6l4$o<1%f+{z*of{nqWhArII-gfu;ciH!v@%3QHzh%gu-U${LUJcp2Gui(S%cWd zxj%H8AfLj+h%^o+oC5)!8h(&$RXYZlFmjtgoj;aGR6@z}?jFMf4=&n=O{B@jS~-!p z9j7A|`8^hFqiVjW(dQHDOg=(n?XIZB)=J1I{q~hdhDY`+E|_$MxW4Sd@2AfPJHubq z3Iw;k7@&1m=T^kqQdS%)qZuT{-=4OK*~VencApL2na_x6liK=|&=YL+wXi41kR=m~ zKUh_av~TLWd&(F3Nd~L`3BG=wXLi67`JUet=5}WEvRMl@qtjw6b7(o=QUpeaUB1mV zxq}D(U!v^ziX>{a>`(j&b7EJU#GL_ko7>9z)F63UCB}>-+{VoX%cxGdeD$Htk(VMl zqwHzrDT5l42HkM!+a-phE}POTteP6m7E6-x9Kvx4NUR-K81ybk-Nx~tW<-MDYQBT0 zf8_w2(1V;26;iP_U%7D-942daI`YVK)anAWH9In@gImc#VV#zzg9G;2d=ukQ2yA~b zg&?qsIy6I~cCgv??MqjhhT1K|vW4_7l*8AlA1wr)-8U+lE~TgG_FG!gec;Qa4%gBn zn@f5;JCg-tPARs$r!8az%NTe8v%WFa`JZGruC`mmxOUof5iE&`CbO3qhOS(C^Db00 zazbD>dm|R0;y_B7P)@cYUia=@@1tlY;HXeG+Z6Gu2><%7=kiycD&Q<} z4f6VEOfGsLMMaDkG6;Ov;YC49+!A_7(|g+4_Zt72zRiRkadxvHI#2KJCO-Y6OZ?zl zeptg?yTt_ekP7hnol{4i_ogvICMH^ih&e2MX~`PYj$59Vs{!6N`cN4WLp)>AYRo5K zuQMj3!rl9L-{!uCweMFZ@u_Emz*~RVcGI6he=nL!2faCq;uD6($8ih%Fb}p}u%6(+ zCv$Ops=-WfI?VUa3^ZZ3vsR3}mdBhyKtP3bSOSC}R-eMGj>n0WJA06=Xv;R-x9dMl zwT9t^ zMfRPn`Y=_bPy%$9Cepsun)J^zrhj*L_*(FKja`Rob#8y_6C*QmEubq0kUuQ-ueKQ< z+vjb>#x^gc%6ynjNFv{>fj@-({UTv9g^?e>7J?8~0XYwCksmzKjyr%t23n)FEaLWS z5z+bwBS!lT@Do5j9CYja=qUZx;9T3j8*|Jy`;|_tMjIdOgAgjGlc%9W=ga!Fi_a*D{5xBENUE9AMZ;_U=fir_RB!+uNIS*XA~#{fTCw3R_8u81mp zT)C-qkLcX<{xbDWwk>e_?Z<5X8kZ6~6&UD5lHqC1Y#i9eQ=ZfO*_$;|uJO)S0dG=r zviz4kCQ`rnE)8R*VL6aqB@N9`eT#iJyH|GloP!`>goMOCs^&EWQr!O+ukotfG1l!T z`l>uZH%8O(zSy?sd*tI;6Ssrd_wV1-yz%a8?=8;PFhBmNnZ&b=mBvjcVwsn8%a?rb zeBd`?md&O(=X2vU)SB;RUBU>}mR*ah=1##d+gZo9=nZcBFHVZ|eWu(Ft2cW5*MYmr z8_=~-ZT-_JI}b4h`E^e3)OwwvqW*g=_aX33=3u|fuI2uIe*%K6w!dvnDk=J6X~Kxy zN3HfMzLOyfudF(+Uu#xu={aBd!hBN}4lW)Aj~9Ow2E{iYr`E=%6wR`fnwf;v;+G14 z`do(O?QuKH)1uy+*gd z29s;ISU%@bVrEkx`)w3CTh!_C_A4jboQGAW=Moh8{X6z@b8;ZL1)Ey6N}r@p}~-5NJ^dpTVLS3VnZ-2qa1?T1&GrW zv3fF5f{8QYq%CD-GVR(oPYf5#v-r5TsXq0LTqpSGOPH{C zh*DXeBnNI(SwWb_-KVzmUe*w4nhR~NA3$?(D`uWr6UTnasq7lklZzbjig~}zdL$=> z0uBYM=)14}s|z7-TWh)Jy_rg1D2DK8PupgD$~2%y`{b)r#d(qyf6{Ka?u(`@NEgki z5-6K}$F0|Go)_G^zi<6;8}x`wgM`6-0k8_g<#r1rvP3VFym?uaXT0B=L4W@Ro;Jn5 zI^ta@j7$O>Tnp<*)K4|Z`Y| ziG>#k){A24ETK84Jc$*nVIwJ*;Yv3YP6XOi{_O+$DvHE%Lk8o5lgityG6r~Gq^7N# z1Z+)xljO6b-E#kg5TXndUMHf(@>CkKu-#SLGF}d3v-&R`u=4@WGkVX+?hd={#S$Um@?YER%`iX2=XnV| zHQ`Lb@C5cUYH|GZkJ2r-r*5WdOR%HT%YL|D-$hS<86fnLE3EtidpzE2KyQr;#9MC8 z_yA`mDYdF`Q(b7P5}$nr?y}lv%>o3dzDCNJ?!XYY6@>+38Yb5orc{^Tsmg1zVNuXr z=nJ#csNz}2jfd#p$eoTgsxI(k8M%;A7Gi6?tL#5nz!4Ysd__5z;-!IEQG)>Ob5C)( z;_xVy>|l*jmAjOEk`z}he`6=QgYSv8Pd?5p%ok2d$XR~a1z0h+-CrlW{Z0(>XBG~Z zT7A3J@|MhA3ND_Zjq#U^%`cHFOr3Uj6uJ1h#|!8zh;i(`BZ%9cJNS~_L;G(^l*M{- zeqQLPw3(qGYAPIxH9>RS(JM_12U!+nqyzt~`-YJMAT!)eC==F2pL_9@EiZ!`aIuFO zJK$u%QS8EF2rPP#Y)-n#V`R{l*yELb6-j+}EnXq}>z8()TaMs_FE{QtHM}jE|Qw@n| zi&}I=C?@Tc#K3^F~u9qjv z_E6>6s)et3VD=#D%PjPnfuU!5J%y~zVTMzMXUw6eWb4s>`W{SR<bgt%9n0 zC21Zx`z|OrdSFxNv|eOTESFmYu5dP4V?NS#>cdj0iL>>2uPwKuF2IB=IAa?+0VR>y zUAft#MK?Oeq>J1`^?%76 zkk5#ywXMkZbESFpv-Y3a)P1Y0M?bJ?bZqXoQRpy-d8k;qZl^gt?fCVlnxi=yS~yG< ztUOhCY&fLHRu#@vkT%rH|0j2dOn;(An>Un?{HfxEZCn-Xdypk?$oX6PI$elKzGALE zNL>7RWd7!|o4ETRow||}!36{C#ZdYbZB0|~nK1`5R6Do&EMWKV_mj|<+d7P8p+wgZfN2SWt={Ye}~G&sUZ-pPm4_an9d9r?M7&W$=-x`7^!R35W6}5kVWor#U_y1C1S&$^xUKRh1^F+PV? zr6}-l4644@-nfYsBu}&*o;;Px(Y3&Y4rg~eFZz6l0(VhZ{6YtTD=V*~y=Ud$k#QM+ z;Pc76-C$R;=k-lGni7t7E}V@i<*Bh}{UYlcUC+leE~~7uN4ouLSToj4AEbGob`%&# zJ^JR=ghUJK<=M>kNju}^vg9TxW+L@0YN$S@rW@OuOx0dJJB7UT`gAvqmDZZeHhuVL z>eBp+QK@fDPQ|2W!k)MQANP!}La||W4;vd8mPYp}XDMHh+1DHs3M--cfd%M1g1k2R zJnUlanaX0|`JdH;-=Q@*3oBRhu;-$HabhFSx85u`gsqmXnCLrgF^p&z%r;b31C=wn ze0Yd5!Vth6g${sYl5txmzD~*K@>8sAa2Q)kl*TxQ+Q!h%s?LKGYb3^)oc`{fLXc+@ZS&AT}Rv zjVVj{$oWTOUY-x4@@cQT@M2?ixhgH_$Ca15;f>|p8!BmSIX}X>F~G>~Tw7A32xjd>5P&TSRFbS(~cTop!-kBB@G)&34K#*O|z|0X>2E zh|dj;+ru{QPQt|)Ei>MEr}`i_p*i=zWLXnXt1fg4ZZjNZrYN)gxi5wdJ>|<%nVjnligP!G@G0?q##vv8nAWID3 z;OJwRq6KOM$%L!yG;|h{Vyy_$r!KAr`h>ChqHNG;Ac|>?B=Bg<9+@BB_M_;oykQVM zr9!*VW1fM{{P~lR$)@oVYI-s-9$PD-SzX&`cw%eKGH<{y7SJ-NatPMdC0P_*hJJBm z#P;3L__5lZYth`7V-Ty9ldZs zKEWI|A*hrN6J}_KZ*fx?qyyhyc9kkdvu5~u)t~Z4Zu7TKWR}j0MghV@O0>v)2j+X{ z92<2IQ=mN*;FB#B?P}C%pLY|M^_x*qMf9AP#Wc0LqV3K6z9 zI)L5(K71W75*?#8?1;*5gcrComFQP3O>QyoE9;SRlDXC-iKw1)RMTQXG+iy@dFPjd zy9DwB>#53d?3Zb4mMn=wa(F<|6fFF9aVZc}U50XrJFFn~5uI{A!0ZsW-!B z@!x;IeV0Nv`wZrB;1Vz*JgJQ8-~6=W?G-kzF#FsBL$r48F-J%}%GNP8h-p9FhdA*^ zl4#YZaF{DXcsQggr^D~N-{F3IgCHO`t=WMVaK({)r{AVm<-S>m9O2SL6c_3=;Jlie zC&WAl7V2j~#*CaFY9Iypt>?&2r#`?5YeJ1CLD}D_7(059+x@o7(wOwMacPcHF`~ek zLt?cTiI&s#JD?O1anTyu?WJ$!^tBf@6;KAgc$sk7r(&Ml7OcXA_)9}FPtrbtH^7lL zy1n26rMMZI^P69I0~5FMyzd1cx)a1u6Dp@i z$H*n!-tzZ7SYEnBo~e$V*J0Bk?O!urU;mQ2%S3M-{<@5oy=BxH$9+|^YO-@1ovv+Q z(ms_6<{bMw&r?G?L||H+ZORtmO56ITy+BoJYdMBZAWwXneUmy*X@P;)l z>0a6?swg%(zuS+x`XV8NGc@t$?2tnW4Qf$iCZ5~=?ai!*lteVEzjC?{4p2Sh1jIp; z#A*Gv430bklv>&xiw9r=@kpW{HB|dJ4T4kXFuY98SG+*(tP*1TbO6|6A)mQ0g{4c> zgi%$fsPLzQwV|?@L_b`@nb|eEB)zA9OX^4$i$ddSD|C_x#s`J-IY)h}wIGUvx%x`j z#|`WAjDN-R8HUt-^GZh4Lg&a!g{Ek5KC6UPxl9Syv)?B`=}&atC!1c*d~N@BJJXdb ztUV;p7NaHT^>Vzf_iZw&Z#!>fp?~)<97ltf{7q!S7YqR{u82a$lFu3NvNGzKvfuFj zS7gt%G2GF$m_3Zam|6!q=%mw9Iq_$AKb3JpK8h@WJhrS4YTmV>RZxUO%Fo zGqh{S0eI@v>pdUh+b|C~?xB-q7WRF}=3n1wfMf42x%n+YPtaChp(V-gyJ+2DJ(#Fw zC7?20eGV5Cka8=fgsjLgZCQvx`u=5nTVIn*^wmHfhpTAxx>FetT!Eu7thz6+rrN4h zdPB48!D<(4~Deo{P%26VH9A zK%(D&-rxbl#Vhg%5r7Y@x6~)d55Nl!-HRBX?}%`g)_T#iIQ95bI3hQ&&8als-IGL%%7Xvwk8-h$X(LHpn4x9DXjft zE=}%DhKNQL$J{X0llGzI;AU*PVVzvDv-gBtW^rtmwsz$o;g`XaZ!|#o`EMz@xN8L3 zz@DW$tJt5=U+2_38uVSfe>-cX;ucFxAcFXeb4rbdgd)khFMuAY;b ze5R}*XQof#s;G_!w^j9e>A&yo6G##M1zz71p%AAS7kZBUq!h_g2^O>I5^A5CJI{Fk zhjWnxX!H)IQI}Jf3UaCrN@%*7b>&_^d~=?yIz^ZS?VN<}Z-zz{o!$2_23}4$KTf}N z#gAjs7*qH`nu+R1j4MA2CzIKfpu@hd(JLu;s&s#-JzpUkb}^^p&jq6A10Sbn2zTi8 zm-G)j$Z}m^9|kp(fziLp45%W`XrpPc&o`lc>c4_AFb{YJ^t`Bjd~OCC<7~8NxZK3g zfY1ACZ^^_(l3oD|Xek@=ZJ-Y4g-|@*ssa1d&!tvuAc_-+iN=Y+wCIi`b7s-xxU`rn zMb1&qzaW|x8G`Wj*Te>T6luh-R(xU+l9}V&k9X1!z3xwO)J=>{+T-fn2SVO3$kt;H ztoUxb;tsaIGL{Dz6sqNkzzkAGQM-zX)iqzhs`_7)-uNr=8{@mr|A{tnV|C~`pF)gh zCuz1mb?ti}T>(!C*XMOTd;V{QjQAFEIXKl_OVS2+UH960@1<$Wp~0GZLh`gV$5?dD zWli9<>d6iVnIQHWP@(&jragPjoZH#ItG>g(qnod0F6q}}hlUUcym3j?*;(}X&|eHn z3GFmj`~iBnd+s!412vJPtg3#M7tB1}jcJePZHPpSj}MH4sg3zDzBwF7!M zRhnRxa5XI%dzf;nR$!bbhvjO3bC|iUho(v{^>e&Pkw58gh^r2sF#!vMe#>0F0V{ir z3x*#*r}SPH(dFnR3PgAiC^yZlLHIzHEeY-&pWc4er###xMZPQKA5I$#oq~3`6b$)y zVGN5$tk0fJD%wFYvcV{wuvl#^b15rT@RnCpwqS zRAIuL@?|b$(w*Pu+0?k`Yf|#EGqc8<0Z5#H(iZEUvNrCvWEHD>GFRKx?`P-jS{l|W z$G#+e6tt+mdYs|lFYa#;|BTe0anCmsxiQt)A;*8A8T^2R5X=4UPtG4GEJwV)>7m3+ zeI=wyy6?7gu064ds^#+^xU2*2`{SLE7IP@ccs4NXWnu+S*kHNDJHz!VYb9QPJ$PL> zRA-Cn;L=NY5!j3^|B*NVZ+T1wa{k#-a~Q(>s&E z!CcYga8~VBl&~9>RJp~7xCj3F401su(Zf~E#@+rG2gr1pBbm3L;%F`KkzQ-%|2L5y z{ykuLnCw_Q^Uk-gVuv?fn5|v0V@8K)^=djT_jhHvOI6xw0X=s-6SsK#dHlV-tyL?N z4?Ub6CX3BtR&y;cp<*;2F|BZkX(}!2%6{D1-FBnDEm5dW*`~)aBb?58Yg)=cO`oT`I29p zke>6u?n1R}DE<5weK6CWf-#8%e~pkH-SZLQ1b@iJ$!2xFbI(KHz|)cYP;$=OTf#7X z)a^#TezE^UXAIR3Z)5S^DV|t$I!4Bxz3RkE2-7GYXEgD@wZq^`R7zRsRMN$@e`I41=1 zPmiffnJ;s->99uzwv+#BQ$5~&eI$*XPgYZ_i_7d2pOTd7RRtL@1B4vFhVl1fIBSVxRR`Q~3^S_|7s&zjeL*G;-~~ zCzua7taMe#7Ydr$%47{ca3n*S$0Y?4teYQz2oL>ubNvEVDTzeg0$1ZbvkeQiH&QAw z@sc^Aks?FFjoPFmj(dvcdFXC+BH`W9665v1&14{l?Fk5#il4=PJb6Mlg17DcbCItF zKB%s~E*k#&x(hO71+s4u3m+x|K!bsBK1mAqS!HEL+jf1* z`e1B4$j{A296K}iiR!OU`y6%G% zDQG@(gW`dGU&@8dH~jd+r}P`>@b5pZ{Ab5aPN|LcZ+}qO`Z=mGw8fG@4_HCA1-|TH zl;v#|E+oD7!n8&vJ0FvrHaC_|(6a|XrBH5LniCi#irch= znd35b!2V^AQ!8MgDsz#|>fbaye5zDeqD%VmZL}G=$@g`!4Minbj+lw%!Se;43yQI5 zs+mLYk&fKxcWAfIi!AI$gh}UPL?JLm#fhp+%YbcZO?yXXiS+rygze2{%_)E{Q5vS9 z+h^6xG&CqVi9hhdu3>$STuolqeri7&Woe5&1LpE7eFj^R&}vOO&i}r8_d+RWK#V(P z^1a%f_|I_7u(|vhc``et_>#Q=UD{Wqgl|~Vk<7UP7Gz*WZEgF=766rQ$vc?VVQ96- z=_XNkEFMk$?M!D}pz4{p$$PSm&c=G|lgRPPB#Zt7oq+#xk9W^k3J_dxOW>;p>T{BJ zn0*%m46O*7`+SlP{$puS^c}isDr9lBefOn&_jOy3-`|VtX-CbYN+MS?D2r3J#Pj^| zWfy9{hL0{7%bio(uOl0psojyxTA;eCH8@q0@!w#XxrX}NU4BF z^i_`u&QL)^K6CMIz9LEQ*LlIR_!f8xI-oCE<;0~!(+W)Ya+h9Slajj0pq)Ek_VQq) zT;=@gJHC7?xJvlAB}ux1MWs!dRsK<)mJG6!G_SQJcT{^pvSsnh9+DM%Do3slFx1f{ zV44Kn#f(IL5SGdgS*JhvBl9CU8&kfn1|fv#I{o&D0vO*sSX#U8B+<8KHg6%F=kN)8 zOnf}8L@QHcdANrydfxYLu4ZD(A!N^Oh6`CpOp1MViEZw@d!8f1$5KwdMosg!i2Gbr z{w%RsLPKTX=az&y9^}sJq@{EyKtWYgi^*J~yy@Bg`w%7o+!aU7h+a`??f@E=ZE<1< zYq^lbV?qjfU0vO6w;TCLyKi;$UDrn!NQ`5|E0EbdIE^>t#MMkcw1S;RsWrR8G|Rfb z6Ag?e|E*O_`-daOs{eeKpp8AS@wL>?pjUSI*{p&Q*u=E_H*(U~^qcPQD)n~7A4^>9 z$DFahCukrD&hYuQzRl(1RC6%!*tw!*r&3a)q2H+2f_q$xqQ8H!xXwiIYi&(KyT9cg zmx-8khpvJ=VpEn)>7rIaPMbUQ5_3vsiJ)IZow>EaXg{a0?OAmc#-EG()<0Xr+Fnxv z_!#2+naP&=8sNQ{T2iJWB8+J@HRg!qy5=a|)tO2!-TGSn( zuMYr%u0ZDK^zN*`tEPlVVZIsJh6V%i*|vRHmRh#kg@;{xmZY&plWy}-G#TLu_HskQ zO4(gMZ#V3_d-Z2yx`bzzN00khWy|O1OADw7As|ujf*(3d_6&3l2)R`(y-C{-XIftl zey+-}#8Dv&FFWw1H+qQyF`96v_OH1TiD5M2{K87Ue%u+b8tY<|flxs^xp4j(^x!PA zj@c-URj)1U=s=KcTV;qnVtHybO~ z$+i-zua&~7NC$MgJ?=0nw!ME|bB}x_`ny$o+ljF+NAKw3dd-i_XW5V@zT8sa-CeDn zlfM#opg#1?^GMQxPamF9TT4Cu%L)3uxydj(ff!_bO!ASEZmQ+RKvU9;aMMG`M)R?a zwI0i#K)}UK8T+YEk_2RU&6BFruln!pA+FzbiWXLCCgOEH!w9IJ6ZzP9vrL z$B{vo^qk_Ze;UdLRzhqiB&8>TF?ED|gDXiv3EheS5p=$Bs>aMw@Gc8f8-|!SEcoCE=hwOC}@TmJl$JH*~)K_s+(5n8qI|k@xr0@X6ijm^ZZs zIMvnZcRS=wBFOFZWo~1Qz-WU;u-Q}5DI6?b@=9jOK=0ot15%9A{yPs34DS;Q_c#Ay zdX0Q2WGhPt4lnbX)15VUo0mZ)h!X2bs)0?8#cw@Gg9s_HY@MCM!)RpBWB$~d8(q&j zL4i_bQFAe_#D_Gia(`;aoR~FivcbOvNI$s8u4@Nc7ja$(mV<%mH=dBm*cs?*g?*{i z(fWb(Bk=;bS6T}+>38HavTT5&c7V|cB} zC{gsdhnJwi4p%0FIt;yiq=e|6pBbq&&{T5)y<*FJ=-vle`PyLEPf8imH9djaVx0j5 zqWY}IQKd=j^q&FNF@=^xdLs}6Ewh!bT}8Al@gbD;Wf|T&mQCu+zmd?P{e;id9F1oe zzr)kr2Gy6C9-i?q!h9Ez2H0I#!Z~ChoaSV+S-C85+lbAmxp2#@9GfV#)+zgnP9Fig zuJc=g4yc5KIi<%_Ui03Wy*ba?u1iTtNnu2=TJH3I_i4L^l|`K6b5f#%T&+?5OuQU| z(c=cAj4YQd0aEk5hX>4&d6rUe?cbAurwojM(_4Sa`WeqW>yHko0h`KS^21-| zPwi>F{WfZ0G%cPvx2-6?0z(R_LSG$?A|s)7&vwEO%}08ahj_+I;Xs1Cyj(3FTOVjf zLsWCdDx$I%xI{@>D@QzyK1lzHZdbtww=&9LA2r|jE zZYi+0{b|nnvoPq{ze~N^b-{wSj8T<0yW)Q{@XsICj`n=cF9=SHK~t08cJ3WrO#%+D zald(7eGU2XNW--6hxX8eeWE!X=uV#nOdCqiQoAv%)g!lUmC*c!l`$HyYKhj3JEzA;@BK#}9gxKQ>Y%k>Vt!+1g zVamAZ=YB4iajvdn{emT%7)z!>Ew#-?~z!uC3u5rgS0I%~{_4wbvftoO5?p z9%99Ym!YX39ORIAg|8&KCoJ$EfG&pMXHB*OI6K=nSwA&SF4AwU;qs(SQe_5mMEKbV1i8S%j>|>Q5CR}T77+m{~;o@)VW(u z;7Nwh$1X`yxR3x=MRM&MSIG-+=TbEo?ZGz&ZEmHf=7utNcCB`&ZGHXtLNc}P@ z073+f+On00w@(dfFI>gJsdz~aX?KZ_0+pMcTq`+hG|v_VRqM1weUEwETXUF}plsoQ z)>&`+;BIDth!?7xZ0a0n)s|jE5azH*02{J=Te{2vb%yahDd3Jfq0-E8f9qF(15vpL zoINN>KvXHt;1^*gLp=lt62YARfyvDBST%^-ek*hzMtAbADv6ZaUr;RttjXxcC4XUk zaXD$hO^I{h)*UEa?2Ml69V)RJ9sE86$&S9<;@gORPEd0hupzmgk$1`gxex5s-SJ*r z^Ez(DXtYixoBLqp@MaGuU52(0%OOCcrBh0&yrqA``!i?h#YbWX;hn~(kws*dG)XC! zp&W15H!c?-r5Kc9f$GUV@2YwQv7FHyG0j&+n$PPU6=|1z+gnkm`JN5ur;hWzaEKJi z`C8{{cuAUfVBoOC%f)_AsX;A80rOls#FvcwuGiLzS?nDfVF~8GZhWo?-Bpe_*RRHz z8c4c|m?o*I^GQuX0ennCLP7@$GF|7qMr-|akpEE}&ud^RRpb8%VDR`md1X^v@-m}O zNWulb3eo7hft#k6sTfOfHV3~%7rr9ZThet+W>BjZ8S}E~Gq~K-^DCyVVWw7)Z=jMB zj`>J1OQXZPq`K{wlwK6w16d&0J&Cwz93eQm@w=a}uTAX4%n&O`AUIeH{(O9X{NC9j zZQ3@k8)xw?DfvcEFV}i-tL4QPdc@<#c9uO590Z%p6uw_ z7AFz@JV+LMS`_eU?O{!0HgTYFTDrLBUsc=TOJeI4wYqdql(ZnW>T`Q{+;N>M zkZ^N14=g$7T6>->v<6u|I(r@LNp}5woPJsxbQHMebQ&9cJS~|Yl)nEc{0FtW?>wAo zd@502(yoZ%e}Zw{?-JA`eFWTAJ~E5;p&p944EK?%j?Me60sIbmAH%C^3mmO0U&wu# zlUcQjF^Xl*cSE1aIn+jsT z+=9F!XS3`1a!tM#%1_m0r(uBQI;Q}e$mHFE3zaGmwq`z%VH+XW9#Z17M(5*X?Wfas zBqGM;572W6DQpR=hl~@LjyDp~mcDR|GVwj_EVOX!_AQO!Dr%c#1iN856waOt?=&Z+ zzN{(ca3~AbpsB_p>ntP5%sz-7d}=^};a<(BHocM5{G@gKq?|7yofypvAJ^-$zW8d+&Zv|MivDXkfBuuU zZ`fFWtQ4TSSrTWqWBJVGe1uw7WsbR}%c!hr(X}B0-{=53o!ag5^K_qlufBq`mG2YB zfzHCCu+Nxc!2~5Yt3N&KK9Z1=%MF5P!-v3@uVbVOoYFw{k}YIOmi+O+yLFl-wl8DmExU6q>ubTK7_$(*f zJBsMq$2U1$TBW{~9spRX+v2B-y8k2TEWD!n-YyQJfTSXw(%lULisVQR-3`*xUDDm% zF(BQ8G}4VoGr-UT($f9j@9+H&?z(H8bM`sU-k)s*WX0Sw?_<;Kvp@ECXavB7S(*!$ zZ3X^r9<|C%1k{`eE}ubFhP~=FD{|JbJp+vM2tjYjz7GuzT^T^4+O&!tzj9aTB-;5$ zam#RQ@iy=JeUhAhARpl5-HDh+MQnS^*=IZF^y^YXBx6F8LMd_n32Tluo2Ak%I)w9b z5f2k4h3?@mk(pY(o^EKmFHMuHNP^<`1rxHYumSALnE*D=CmrMqqM+f+%wE`37dF^G zf&IDOZ+hVklSzi;t{VpVWTKgo(ADqu-bF^#{8Isw=2Bk5Ex~WhJlqDS#N2sl-CRD{M=#uWuhsa;BuQWw z5YqYo294J*ndW&nN`Qj?9A*45#a(i*4y|I5*En2VH8_`L89!(H>l)$Pt)8oURo~0U zp3+eC#%1%3W=v3T6gEh_3L~@MgL0y$%J&S1RYq+F3Rl3*41IA?JpS7)E z$t|7v#5Za4wfx54@Ywj0bs#9MOq5hUcb}C<65W_*tLobr4;1EKRa3}_sw7#Y@A`d) zQ|#ZMa8P{Gg7LK#WBu6l@nOLLN8h&d{isnsM;AmCNY{+}sN`pZ%JlN-##x}I(c7(8W<0t&rc5Qo8CHcI zr5Oe40y1_JnF|Q3{rLK{aG+qGr;#HvBip-(M5R>YtsXu7!mRglR7MrcTcX7m^SYR| zoV6;ytm7N=nriwjZ2lZ)5)<~e@whS`A1mLi&0NM=WXhMDD#{{o$H#{G4EE5b&V=}u zv&-mMHI`WZ2C>wm<N!K!ssT&}1eUvO zfu=Yll7(5)_P+Nr@GcYxPzebDx}9^;J^nUcU@|~YOt@r@@>`T;-P#>!G$5VM?wAc} z7E9&71~YQIn3_5*(1`Rdoe%EY6ur?Eb&tbSAfO%nmLti^(Xp3SP0~KW9vGFPRbT(9 zk#*{}JVr4ehiyWnN=Zy7iDB~HY$RqqWz{SN%n%+!OUYqkdgu$2%n|0IRCOGOpau66 z$NWZmOo8_+ZWP&{Ze*-hYFe?^?Zi?B?M~ndC$$Bdww*=*I*omdCXij%Rqf~DeV#7s z`3G7$XJNFhj)w7r2}DD5G5YV6`yYpc1&6z{v*<5D#eSuLjcLm9tF$lJ3b-P)ottyp3Ct_Mx%VM_K5IP)e$B699qom^; zT2bzaW7-Rfi+Zm9{tgCJhB%qsFgn+Ha4nxlf?fHtpdU6PR65|xjXk1jc2v`|A|i_v zX6q1Kn0=(rYJXxhBVN07!t|AAs%2vmxBK4b9Ej_dA1-_Zg<8bM%#7ahxEy|1vyST< z{q1vSxRuKw68+^*Uk7uCJyHOQEsrR{>@NHUwdXOl_i_rH_EduXa3dgo-O{;z+6uV$ z-b&ov2JGK73Klw0N;KqhIy}pY-zW=r2K+@lvFAVA+TYi5`#Zw|Hu$x>6P)fyKC@T} zMs-4tHJT+x_|nPe2;CO_XeLopetO1?M?(V#m|=byO_lU3SI(N0$wA*~cmQu><8wQLg8 z{hi;+Y3E}DQ;zP3X% zB#e-XLAIwYWd#bN^ZXL<{LHF#Xj^2)tU6Bq zV(-!jtjO2Az}oT$Y!_fN^aDw4qAIWLjbqjCJXTq7jeg?zYZM^9w6MSn$`zu(#b)vW z*UeUW(Dzo~7N#gfMBU$`Q65V~#IIQ(^U3H{m8)X|k;R$)exbPgTUZ4>w+!&D--Mb9 z5TGpxi>cx)MyW=;S`?GTX;&Yqu;%iQTtdBy2vYQfpgyPfVeiER33ASJ;_4<}K{gE^ z+dHiU{vM&ac6gKkHt1#gKjB-6TW9^NkF@hX;2QlwYg}AQ&fw51nXl#Z&LmmV z2KgS9vgJ`HZ3mm*;fuaq01OF+D)b-E1;bzg5cT!bifZyHSrEZyqA1f*Yb{cB#nX>H z@qOyy%xO6V+ba);=G_9xXF0qOhQB!x+$OmvcG7Y>fE?4fj1_R5CLMGrcwN5XHT&U|{@v&k_g9+qXook;Al z{5Vq~7CKz>#WBfGzr5%XAdUslBD?miZerub8;9ZpIwKw1mr_#ZDBHkut?1%fjqLuI zhT>Zn>*$2S18q$*_%hO)!UFIv1#TGy0z-A+?Tpg zIUUEo-1|7@tuTFZL|X28#ICEivJm`s^K>a841KIh1>=`TtxgI}<;YGIwzw)ek(2is zlb|XBkPSvtKH}=>SdmJYpIY-viWXRxFoxjJQ7sbGAH(i}8FsS?fBxR`%synaFYq1&f4*%*IPN80wi%$TKI;4EA`6A|Cf{kXhQwWBml`|3Ur| zE#SfKkNl6XIb$nsz$ZsXvYqfN)b$#^p{vEDfR>@E3Xh?-AUI1E2ibS?CX2+F2#oAc z2Ov-o_z#E2>NSd=$3#Z82|eAJvxI$@tW9d*(0%MS(kM# z!+o<^6|3gmyR8`$T-Pd!5#blo4{_igt1s0g>I?v{@o%CaXYw9iF%PsQ!`P>tZi~Ao$Lcf1j z@RjTY3bl->zII=Kn*hO(R3ihr>uOLumGX9pr(a$j6gHJBSIz13yH$g^-;#B#t;AD#4S^moR=G`*@m1}b8z!_OSY+5ef{4>|IHmu?5_q{pWphn1i!P)liu(v zMqi>@u#BP;yjufZI`k+$pcx3y(zX68nkpxcsuSa}_>yBJ$HPy1rJ^2HAt~!OY;uu`YN2P#ks|bo zU)+inZPc+9Uov(xctIy@@{iAilQS@8FZ2Ln6qkhQ6y_zNfwsOS()kF~x@Ki?%l*UH z4ZuivYN5z~Wd{?vu>`exjinAGg8lQS@2&;a&l~NAD!yG_RvjUZ5)WYTmga@Q3}*Vo z#*7FSb}`EzEMi*qo8ZC&tg;#86A?-6S5={z8J0HKuE85yTGu(paZKdRi)jXHKh*VP zz`TZpi6%9F$gG+r$uKo$nVDg2@DILCy*kL`GPaWFIYzwCL(ebZ$4XO z8QnZTTw_9N*bXx5H0L3BgvuFyqBhMI`|YbY9_O)O?T>fsDVm;We^vI|k!?#_c43a) zJFX%}FOc*C?PHeq;|9OB{c-_lR;v^qx1JD_ELnlT9PoQ0Woe%F)~XmYhJo=9lOH4` z&R}qWS8~An+3NHuklU|PTsUqh?mir)Z$0q)>nO*r)~(~3GQz%@vc!|8Q!!;t)hMKL z6XL!5yz|>}p}0)~!~kD=T1+D;ziR={h$Sj~Ydk2U|E1`zoJQyn5TFbX3V2En*xk7d ztvT7d!*OJ9KKKpdy$~A{;xRPb7aap)nygQ!_Y&W{{45PDIS~I%A}=1_;Zk*PY-}yu zOm4JmQs__RC{f_zQr+I1p-@TqOWUV*;j{B!E6)3F+}?_&?fmICWvP5u+qw1Yd~V1Q z-FD;p*eA!u_i|2l62S{3wM30wl=hl|bO$b#I1-m&v+M!e*aw#`ee_DtG7@$_PJ@Lr z;I6Fpd(-2)y1MBI}*Q4;LMIB2)oWp8FX-&*R}u7$0)b;D0{g_SK&2$ z?*QKorG&a6n7fuYID zC72TI*KNb=XDF}pVZJGmQo@W4q*rxmTDuMrw8`S^=)y1-%@xS+{uw{s151hUHW%ut=wIt>4o0CX?8hkd+DfLsGV>bQkhO^S|qEz+{?t9J;q;8ba zE5E9&?h$|>{70Q_u;%&eqTM!%=uU(>YYq{ofLWI3G|r-c$PXLisir)^nIF^@mru;j zspmRPkb`YXgY>{3!44nATDB=S^{#8e?NMwQEMqE#aM#E>1YL6>M%5X%vSV2di{gQ< zHmSXu_joL(yjiW~btB!5yn~J`#+NMmUpD?)aqG z%o93np}W^ve1aAJNn!7P^0!y82dbF`OpL| zPxsZ2)JH=&WwY4!wWhsevd$`=??eFmj^6XMefH%<&h52``>&!3chKIYXWFXo2ZZFP zV3%8K!tzurdhqWTo7Tl*+&a!U)nz5q#E#=&gjdP{`I~p@(I==WS3>a@F^ zpm)i`#@$`|o_@Ky8aC(uY#!gyPm@gi*O?O@SKGC}e-|8KsEsYH_QleGFo)uF{y#Gw z&?0{SJkn;_OCu)vd=dXF#f%9wOjua>8mMZRxx!!a;ALZ!g3%2sD700nF+Djo(uf%n zJIdCpZWJCDp6`sVE5gC2H#c=!qG=Wk)rnwyb$aBPh9d8B9)L!FeO*>clQF^^b*(+2 zLdzXfWow$Lwd-VJz;LW2%NJUwL~}1DTj~VVXT&saDnrT1L9h9h%{MXUT_d~%waX$3 z-)!}spEK^xHIC2td(44>`U71WgOf8QBzTqQ%@YOmHw zmlsl8+aBHbVry>N3x%mWz^wHI6(C2-F&|xgHa@9@vFL942&{`P#K1&>Zllte^IXq* z{yTLHRVi6ro=+OBSJJKs-RUmyO@HQ~%k*e*) znWwLsA2Z~ePz3TL;YF}|7nCh&n$W6!9$_=w+Q6ZTHJI$_3c-&QNj5EXp$MkRT9hln z|2=40K~2P+1qE%0Dh8YuRNZv2^Fm~Dh`18JK&WthfZ)%}C0Yk(b=fz_?j;&>t9qV! zQL2wFi=ZCocAKGvkBi!>K4E=<3P|Cn#=8$-yGIW^f85{*pN>4ENb3KP7~KzJ-KPM} zq3vb4yP&^5IxE7-lGJLJTqUMoUruM1PSh%r`mNqG6aC31Q`0MRL(Q(|3;DgCz97X- zxURg-fDpH$+JQ#pEQ|9AchqonVC(PWqoXXvs>-@I&Nd5%yb2n+1`BDrD$;nCWOeFt zcvD}UWQaa8&J`{zeY9REKM|=)ybQshH$>)t4**gYQ|e#aRfrlNblScjXpkAhqm?Xh zFdc0M|DB6hwJT}4-vOa``xvae zG3G`M#X_Y7L^rB7Tu*&3&w>JOE<4{(s{ht3P7D=g!z4%RIR7Bww+S!@#&UEJy$ePX zrvP4F`GZ8j(D@iuxQW-c=CQ<1FvWPh#=jG9M)z1v_a)R zA@MXL!K3&NK&r@A%>jZXMB|RvIZokAA>nj2b8AD*r?}KcCb5J+@+^YXN#`0*6m;vt z-FdA!jJr;d?a|fMw^n@cCnrk-nghJdveX5l-y#^sdKAm(>p6(fq{0)3w{cFdSLc_R z?hfDH7}R3vQX_ehkUE+F)%s@B4y8h(y9Dl#q|6zZL30{z$1}>$&ql5%N6H9SjdH2o zH%Pv9XTFP;I8t2l69!3H3_&D8J=-`QE_y!I0QgoHh!G5lesNDdkp7;Q4vRh5>20eG zA^yp(^|0r(2Fx_)^u3Iyczz2-leoQEv=0qBwMt@AI^ zq1*k)R_=^R(JBJyuM9@hXzIl;(&Y;1qQE&S$vgqddEpYyEd|G43l;7%N>kfKKz$h8Y_$-5ldY#3zrgK7yGC+8o#p zdVNVV4tlg%y@}(7L=i$0yu$SJIjRs9-CFp*tM?qPmaRpe6>x~Rz+yR#y2xSgOikg% z7kdQWFiCR~S7q%N`;20z%iP^XUL{0USJ5O45)Y{6E6()3IJz3q*%cY+ z3MWLW0SY2Bw!OqWATI1PY%vxJXGnI;^l8~IR}ncO(^HXd28&nylu`m&V0s2*yDe8! zat6?NKbs|QYno*{=Rg8D>gAskvMnL5iL&{bv~QEVH;FJe;f9NxMl>S20ij6zVQG%h z`M>UOLDfS|a)o`QZ^h<)9389}=?!=NKd{hqq|RfAY6T^IR0hO9i{KCppcJq-3%p0A|DxIw43lk4Thach%c?my+U3x1pxu;$XRb4Az3PLv{l_B5 zUQ8)znt=g3C?kqXM*1Q~cKyVkzCYGp(au(=V!7|VhF-$Dq56wP)5jPptXB1T{>_{L zTomT0uo>M|U~6V+ZYv-d*X54Qv*t89;aC_Phm3cj0eB(I2i=b&)w6P=WDs=X!tbLrhk~H3Y7UsX_TzGv0Ra0`6_Wu*ktU=_Mx zKQOnZ4$=(NH8{4UHJ3&@A-t2{7~AvvJ1Z#DTK>jQ)!7;amk6@XOHC6rZQic_r&IfP zEG)^{O^jL%I8_8$h^kz$)|$yHBI=_?aIlK|h(nvBOk5k@sP;K1OOd1O# z5U|6&|CNT_*W)FQoS-&!4lW_qA#!@+o5=XF?fP@;l9F+6$+fxl6)3|U4&``N5cRMm zf;^xCh_p{%7Egq&C{~yhS)$YlNf@%p} z(B7zL4B5At7~U|Gi~iMm_Buzr4HXc9Wz}pkC#Tyv*>NlH<{(ltz9gQe%Es^DKGJX= z46{FHer5QJ9@3+DlHDAYbyuxcAEH=`n&TEfI*f$Yk(tOu%k5xg>0`1GjZ(@GKr=vPqyb?H1Sk3!t0xAniL{Bi>{%Q2x{J1t^AOAPa>MRPa{Yh=@ z@y4hJnub>{n6^{!#T-i$yRs6$jEXZZ3}OFotn;u$Y%@vd4eRyt-KuAFq;n(pYZVXF z6ZVg&-27`VXXg?GAu|-{B6@R#1?KOZ|%{YcBuf@4)y$WbujTsbQ;@-Kc$v z{W);Ur0517;5wRJNmW=GF6+C~?surw9$zc${$ZRE0&?QtF*C?b3Vfpqha-mbz2QUG z4&B3|bNOo?@nX-8PcPoLpQT z_;*ILew-iCy+0dXvT=E6rv=k0T%|ZQ`BYnj$+gmcf{Udz*_weosFVNdn!y`lk|#E( ziHw^$A5SNP8Td4ago!%V5fL%W{Zw6ih1QPX;+d?DzwlJajWWCfFvv9armsa>qGw{TgFXsETAc ziZyv=5(;{TxY6A5vgfl8^iOg;>gXuQLH%ss8xf10h@HT@`*gz_Ul>FA6MIv0X5ZGI zWlYZzQOAE;Ughgudiy#i{Z$eY6wAWOV1d?FiFup&>z@!a4qM1Kr(bqTtwB#D>l3~&t_b%8& zn*sdoYw9$}q}s051#jK2eU(Z2&d=f)U$`ld-{lZNyq)3XZhlHy94f}I;~hc$Rt-r* zl^cj$(oZ?VaQm`x7IV(o##sE^sVSzZz(T*Z`C0{h9`K~aMU)h_diX&nRStdz*IiO3 z`pxG|qH^2{f?|(^Os^ie64X+NvCXO1j`9i%T#ptHhV>!D4Hf359=V}zv2)Pt^V~2wcQcz`B`lg+ zQu0z;T;acNor`Ri(UO){(<^fKDDu^R(V5C})!l)iuW@OWSuSDD1TpN40poJsy40=` ze#pAt+;EEQKzzq|>!K$-^-lSG@PoHZH*b7UnM-eV;lR45u%?Dfrbg;KAC@0gAGc$d^|GaU7m#JGVn8knLjP91r~e|eJr;(hNmRdg zX&HI0&G-&rI$#8iC@`?}r4|Og7I>sT+%MgfhM^S#9%(j3i@;x!>FhWO&wD-=`ihW3=h#2 zfU-B(CjulC)|K^4WyY#XAa@$E+YTK_*5VX+uh>r@X zDQu7!ZQIP<$Q1HjRG)~dgJz0x8v6U=1$Yv8(_L?AJ~fK|B?^n0ZBa{KwCXrTVQ|5n zgZgi5D!}Y#Js=cocMlpzZpxt1cci)Z@oH6Zwr9Y{Q|~wl;y+0mAv~Whvx?d96_F=c zWg3*fYsR?V4Ny7s*>u)ff`(ipBVv zg3jdPGC>z77q+j&rdzC1lKczLZ-L5GP9sBYhl9$zar@Oc@_uy|eyxskq2lR@Gxr>; z(nf{>1yHEitNHZUk|Lqbw!x^D-*)9U8a9bc_`(eYZ94+HIb?f>lMv^3RqJ{?TO!hAcR{m}@@#L2`-DICqH`ibPa?upg5Kl}sCc={HA?W8pb&P$9$Y2w?l2Na442bF zY>tPiLce*ozT@TtA9S?AoSFRqliRY&>4QW!Lh$*59islU1rK1w`?9m>9{eYCl%npE zlDi&C7*>V?^@HQ~xQpbT2A65pr$0aZ%Y=E0VF9YVI$0|=0(A2HCclmaKqeDsq zgmk)YPxHJeg(qm4kNfMQutqcbrHsrazGD|pP}J>6+22>A{9G=P5Myh-mioKpM9$cf@i5%F znbUpk-m4WfRjg-jRdKg{ioQt6h*#h2F}sZN)8)BX<-EM0Q@ae)^UtjI@OChTS5wgm zi91D|SQqXs&LAD)OLvmn)zo~80dbL!n{q=(zlJK(y6u>+jua8kYn%64iKe^c%=CqB z1htLI=fRFp@he)2#J5>R7$mRdPmsQN>+fjq4Fzu7LB9vj z?+LV|i>Ymjg%uI;(d7uQHeQkj-rv2dHP}uuC&mf34P!XFX>SfQIn_q|p2q__oY`vJ zeG8!5K(=6Cj%x09dz}plnD$YOS@rGb5gFSfPxfG&+%T0wc%~ByNXHHvz;4HE!;Vx3 zT+(|^ZMe@{xR+ZmzNvu{Z7h^i58BS1^}O;Jl!C2D1ZxDR)?=kcV#+T`Mmr!dC_J~&Gmmvvz@~6e&W8n^OO}MCj9rIGo$&jlgLi$Y%QWTbwx4q$!Y4Y zW&Q9tW2M8TGQ)h1>WI?`sw50wYWl2{6?x>&WjBb9Brlxc{IPtL57+q4_k?4(;Tq{&RNvXrG2 zlEbap7@n(~FQFRUkW={M+goh;)m+aDK-F~_5J3|TK}83^P~b-H-i6@;Hv zI(8=>@u%hRwj4;V@Kz?-K-oHYQdbDE`#L#;K`gD3m3xh^4y?PCib}n)K)DmcK)(@%6 zZo3F2{6=g!em*V~%bvYYIjrAsLHe{S*uAmP{e;b3GCxH7t6fa*I6R$5+%Mp5_C>~s zn^ipWfg&&Iw9poD%n-o@)FFiU%)$5+1$Yx08^b<%imfXf>@o+Ixg;}qLqkmO`1W0DQrtTY`7Z>0dtUzjsQ5-*9UY^a-xo+M z@4Kiz4XcNOdsS9^vW_1WHb?uXmj&%#2&- zpi|?0wj`HDl^BtF+sNg-OQ|=l)0U^P0Lc?;R3hi$x6$cOtQ$U?Cpx2<@)NoGC6=s6 zQDp{)64S=NMH6FG7W|9{@s4n81aZC!B{rPR8sUEPodz|2IyGm&_f?h-&?1pTq*L{_ zF(*SX?I6@CD;sj#<36pwHR;~IS+xuN=*x{YX5<5u1DhoeWV=2tave{DC!NZR0I}Ug z5|?z0dEHQKDs0`%t9B`#*%w=$o2%{DNpM2FgrC#u*gi>;k@+9`_##3UL?TZz7*ZOw zB?_u!M1$p^tQg3D+mK6Emj1A~6gS2$X`-sJ3qu4v5SoF!)#%iIS!jzd+Au9~XZ_h+ zeUBtPPW05mmm;{o$GNJZX=C=SXIdfG43Z+-!u*M~nJH9Pq6z&X9%f7%i+80a!?y7! z%llkQ8twWLi2Hi*X}-i%amxklRI0{%Jxvds4FxJvbdz5PxN$z5P}GWS%%be6n~G9= zu~?#Au-Iv+8ZWk@L__W7!AZ0Jr=W(HOm)q`CAh#)&!NZx(Q`sF?1TM>E>1sd5$V!Y z|KQK@IC$pbZP%{sQr<|Bvx`o-j=R(c> z!kwZ5JdQ79OzG_KYV0&WLI^{EUni8`4NRC@Up=iYUiVzi+BFbN3>x-WDkLHhyomGm zVj?q`z&wA`08z|V&;Ez=iI$TaM8H#Az%5{ysC~X8yQ(|wemZ()7);frRR-|4`}t2~ zMqU3M;qUUr{de8l-+zG5)QluNb1L8PW+PlVB;n@f?3{H5nFORgVozIwPH&PzY{H~*dmV5u2<$R> z`S~}yeWF(x1;_%w$IpTOR|($-ihS|sKycQ7D-0lef^%Bz^h}K)+NbBr)|CnHzdq`B){|#8 zt9px)Z%O&5yB%lo&g$@^4Y_QX$@|n^dp%s^`TT`kq5FF8ld z-VlYxP%S2AgTgljiD1k4#5%2Bj?SMV<(3&Q*1VL?U!Q!a)K%4uE>uR>ujTxzk%>BX z`{8UP!ela?GoPem>-nzxiF2(xK)Je^K#HM8%LD0r(&qYvDdgL*oM^&clGcge0YM1h zB)kRSsbs=LVJ1MLnPT2MFHc}(z{PL{niAMt#VS(unxHX5<&AY;o{C;ad}Ng{RSWX(OGuc*1I&#$WUwI)3x=Eod-Uk8$vYYPlrCy71NT- z^4@2{!xgAi8+`OnIsDH~;odh|EWfBN z(%8Rsa^!SaUFD7Fq)j&{4mDgr<%|6u!)vOZft>I2UNNtYtm^JW z^{lLWHA<3#&A+ZYTrrPPPoG#HbH>7>zGX8UNyhW^z1GB7*cZMsmZxRs?$F$uVXZ3ls zu=e^kHoAweKD6UZ59w)JB^@gtE>HLmeU?W4)4&5n;&oQg(RwT|WrA3OL5wTglOhyxU;HrB&1RR=#-;AzSQrMb~(fA{^ zS4Vatlrz8ExQStBmhKPEtMTGK;fc$CKmY)G$)Zq^<_Aa$K%lr8EJ2UBz$8P7z_J67 z;?KDNTwL7$VR&q83|Y60uEFsOFzbP_aVw!hc+$sG-)z2RckVQ##{?T7DUM8F{KOCy zn0nWkiIaIPG>O%x5SQup)(gQU)a5I$&&fHPQm#l*nA+>fn07PC6^mmF5U~F|YZcMR zQpV9Qs1rCV0AZoBAlMPe&IRH|XiqLf0;)F>bEhI{DMnLcjVUAnl@B&qSE(j_x!$0d z;T!E(z(98Xkg-Kxo=GLo;dbxS9A=6QmHpE%8JG1-3pIa7Ks(HsB-sp$vRl*+1=7lE z5wAds`)}y(J>zDgy$@1FK;h;;<#IN-v$iAr*bsjF?8hbbNwowmP@ly|VP!t{pn*pj zrOet~*CWls%)ldt;0=XYNyYb1wCr^iWK5sm;+MfQK0gV!Z%nO*2K+sLUO_wxKWrL( z&wi-&eTvV!Zzj5zWib2;AKZQHnmYCLPt(PXyhR?b@YHt=hwGBP5jIa2GdgsT=j_>e zLY08vJTG@#mK`>BdwTttx|KM;YbXtP`PD!~H{PG0`vohSN;Egc8j{CrbB{2E33?v+ z%EY9R8TUSvYHYytB%A*!y-5hcJzu}@zQ*IgUElb8+Sn*=;Fb$3rZ4b3Eae#cy7P}i zb!w<4rm}$M$|{D=zxgHtQN%JQ!{$2S)~FC}j3yOY?0KG($lKt+lwV$`f~Uan^b~L? z%4@8#sK4YRuKX4}=*4a_CO^0n~19v3jH&+g=k+k~Emq;nL z_mp&|1<-}6+8$l2Z~cTH);s#J2@ilCc~JR^LwDcTvG!{!p$V&9F9rmSur9Gu8SlC8 zE>!{ntoT=RsdXvdBQ z(>aO4oQ#QOYZh1+4r0eHM{)DTBPV>~=x{5v4LOW}vm7l)Ehf1v4K&#+r!bRg&t7$a ziP6UugND907vGXpEh}*7+?qhPSS`nC*^=>xJ*Q2b$fwT9sbkyN_gy*zXGZYaF= z47c0waR^P=f@orvs{8j@hQF5B$1T-^+hyA>f01h|iLRM!*(Sje^fC7(_b>~y40oln z{yO?n{)VbgHMGG@roZDicC%>JThPZeb%T@ws)LS@x1Ux_D|_FP{BvI+%Bt1Uj6YnX zg5KQU6(8Rp#2eu}u_Hm@*GupQxWpr=#Q8$LR}Y!Pqq66t(V&s(!-{y#) zX`dp}N^r1wwwANB0uQNiId1K(`_uhrajVC_o!4h*yf@tlBp)}NANl^P-Vca+l?4jk zlb&Y65rEEQMxVM|v-QUxzpYU2M9sF8mV0-8EKT>TyMxjpsh;y#TX}*h^$*v;N?m?} z*uEy=X18WF+>g{`ES-AbiBy}~^E8v6j?R;z>y%5yc@Vnv&aU?|@}bR|isPwKb^Mb{ zmLE)1q@CkfOb>F#P)2L<);mLE#SVXzlCT4`Vw#;r?V9nUHs?-`Lp_?1m&8rb5HZRm zh!d%BZ?%RPmd4*g=~U2n^+(Jl^`?ed%Y$mJ*@{p~C5_`DkeeQ+nzk)HBa=>H>VORz zB*E4$=+{4w-%J+Mqmrqw?$6K9e;Iz@ky@4X&nkrm{%IiQDHvbn>Eev2U0^K?eZCSG zufzuF#GI+nS5~MD%o-B|U3aD#xv*TaCMyBsfWfZTBe-8W=EY*jjw(=eYh;@%=StPH zNbC9izPI)y+3C}3Les`fnKIhD zNA!PGQ)RM@BeF7JX8KZ5T)zM@7$o?_D-Xt<2;8rtxtzE`Vc37a* z=A%p$mIY-HH&>57Hsy9LWXy-Z5m_vRH-k~kV|#wddY?h<8UOfN7V+^R!!)oAj&wWW zj3aR~tjRBMeP)7UcABG|MWT3cqO4g`*KlRjq;62}$ zstFr&qfUpvy^7F`8jnBEVF~0WmM~`7tNNju_!)rz*R4~;1e@YSy}|bh8TmCr26j$K zkoGnjDEV^NiBV4QI?l{s`W&5dt+T830-ny+9gzEQIv%Fkm4|vU6MfeboiA#>C7XYA zhEQSU)I;hnUdUxOKQttsA8&ejv3^=?F-fVX7iTi1Q>jZHIDMqc6yw0}v9nD(T%l2t zp?jJ0lPch<_VKCtEIIWX#Qy})1KrQfLywP_@yCg0YUH~{VIDW-M<)sQ2;^UVh?~Dd zw-TR4?#n1X2V~No_(Qvo=_}EHs|-b!|EO41!RL{dR(U;QF=-BtJ`IY3l!@#XZR=+H z45yB#Us4nO6Zfwv_~%)rp853mkpp5VamY$`A08{a6L9CrTzn<@{trKG|UA=!Jvb!`{P%0EbY?Jq7?nq~=! zAjkrcTp_3Fqn4AOdhS^YxHN4%q3_ckQ$y4N$T$Wr$)%>`V|)juPS#Zc69E6cp3?{KdJ!v9VOnd`|mMjF`!~ z_%dUgR^({AUNnQbN$*sS(d3gu2H%Sb&3hyN)cC?dNEkYhfn1y#5=Hf1scN+q( z;a4EkYV!H_Ct8@oLECfuDuo|(zYI6>1C{3D#?`_Z(Ot%e(Fj1f4qB(YGEY?5P;awu z2}}gDER3b<)_QWnO+c@=%#pt~aeZe_9aOg&bOP+JnI`Trja#l+nWc$-lq1yKij1Wu z41v@*(HTfsBiBxv>j(vgle+Z_rfgrmtmv{+D=DoCrPlJCK~idFE+xU>gH zRHJ{sV;>tlg1-6ut2L;dvqdEEQ~Hm~SLT92dou4^Ggq{&ba%8r4hTgR@A6G}o_u7! z@=G@Dp)9u;xQ{G5C$SAR*b~z?pqz(fObXKxanx16_*iBwqWyE|uz4u7mU}k>D3<$M zJmC+|lYN(jv)Jz{WnMnGGPQ%l14@>2@0rJzyz_D8n&09EI78l@psDifL+;^_^Dz1S zh923<`z<^0^qsprdAiL4g9Mku^BqH^TzIOT-*w9Cc9n@-V>MCoAw2}Zdj5p^WqHQ(` z(HG-k{s$kA+^AT!D{*D8=QsxmPS~l$eSu5f?4;hn{zZrz%3z!?!2C*2XH8E(=oEP% ze8r5d>s^uJq@C20SaF`pS%OuOYpZ^NsDNN9o^wUsoBN=gyAmt`{n z`HrMgKC7$-sTnRe)FNDf1N|@qrX0K$7){w!y_Z1l@TmD z^}eVE`gjIPzm<)V2%*07n|gFfUuo{X_S1Oe&EI*u_k4TeLryBuDD?E1Bsrh*xhL=l zd+}yQ=5Z!(rCaFoY9xM0j!{X7A!?G8UtIC2jM5<&%esKhN~dygHaP!P0Xd`RQCmp( z^)UibZ1>NWDqrdN0#4~XH@h$urlqHMuyAZ&``i|C>HdSI;4-zXNPxsVIdC3|&Ab|` z6%tWi!gf!W#^4nbIcuK8jiG(elEGWJ3OaaHW9mpUP1DfMNnOn_rEZqa)L+3HWYABF zR$#x5lx(K>T5WO~%w+^>v~Li?@@X`3nA;@ot6x_;T4bhIGiCT8Rm3N(^tO!m=H*Yh-R?bD|}t+Ft47LR}uWAh)%mI$*gI9bqs0;eMcQ_9Dqfqm;AvRpRkU} z0-c+()2unoJt0!2`M~K5GrMSEI}YeXeZ&+s!L*Ptls_-&9cMb(LBktK%Phu3y4^p7 z{|A;qX})B4S~+Jq@N3c3qA6KXi$*EQh+3C`;wF7HN_y+2NfuO{b?LV2hitBWN7h@E zkvd54Q(A5-x7)_Lt?ZjbEqE`X(bI5ZT~<=et@m0-AxLz;pVL>wG5?U9mQ>3_adHF&N0jm}JwsE;!Xm*}dD%x69ZCP5# z=W)I2KSJ#6XQ5=y{=qdq%UdPcC;2S)n%)l_3W(ZD+fen+9a0`AlX^DM;YOxb^oK(xP!a? zw{A)T0+vGDTQ=B3g};nqUqR)V|l`|&re6(Lxhmpm~s zkuk^P!yaT_)RtWKmh~2(R>HDy{rm-8!D~wnfwb);Wy#u-_MNz{kPCx0BvmEQp~^+9 z?>{OiQ;A_`T^B$=uQf7rKk-=FbEj)%p0M}0q9 zd#KkBKSq7H2^=1utEY9m)?iq4s*#nnl<75n{!Esx6rpa;&o)8m*ZveeiBwIpO zsI}ffYi&20jOz93s=@8Y)z|OaEq}=0)KBc2KMNcD8BhLm-uEbu|B)~9*T6x4@@qbV z&A-%Z{vC|B$NL}sWH<^ufAs4-R4sn?VGo6&L+aRqo_pU~2W}5)lHSLbO9Lh`5o5~; z&K-y;^iRGqZSMT~cq}@h9=YWQEOOlUdOIKUAb;u|-WI&>uXEq;_04Cz@0VVX?2$gb z;4Od4Nq|{MnN;N3A7UbxLd@w7*cz)Av-GT`oDQ68lxjJ@8mp9*=JHYxi}+j$S{sZ_ zSeF@w(qxM8C?fAcz1>cH58@&T(qA!-<6&?h_UIciMyxe$fs+X_639dm+o5#9YK`-Q zXyP$V(q|9w5mRdD)1bBCe17Kr`)9HCt_7{6@~MrMzPMJ!-os8Ri!{y~&$>!A8XVSC ztdSnN5CgaCLW&!ubi;{WEf&dJPU47@bE`09VW4tz$cjM#n=umZ{N>A)oOWI=H_qoX z&(F`4T)18qlro&oPa>U6Anw|&x=|D&C-J15SZ*6J1XA{BT^XmLtw&zluS@S3+-^5Y zDV)z|p58s-Cx_CC>-EazYXoq3H!uty=N)^vk@8M1B3)BzYz8npU-rEncZO}-`1JWRRY^eZ zd_FUsPv~5zNROCOM*0|=X@c|j>ixbaj9CQWAbm^w9zgkH!T4x=ah%{vy#folNVZq4 zU7jb}ZRafS-o4{|J{^nE=jUg>e7+FEZ@FDp_I+!M&h1#N4#U9v_wSE|Kin2daa*$G`WUvsx?TI5yTaG{ACS*w$WIYm>7=9RR5Z7*Es4^Yil| zi9Do_+s3-CO^$a5c#g^dN9;h~j%8W6Uatp$>-)RUg91?QW)gin`|C>2W@tGtnVPG( z7p6!`L3-CZ3tnZC^Ug^Ca}{6`S|5_K68K!R$b4(b$E}dbDL~0M>!4WHMZU}aIeR}} z2jd;EegFOUeE$6T=<$1G*d9Z`*L8gW;D&KGSf?ZwBSfZY!Zx#~ec!RRpjAFVkug#@ z*_MSbWSlaLR$L(Sz7v%}S4CJ?;Jb!=xqSV1-9V3YJm`a&lQ|{` z^G0PDJWo$&rul?*GoLXwEJ+BH9m3L)jDG>h>7Y@so3 zA;tr+9cuoZP+o&pR1KvnC>mWAwtz~4V#UI~YvO^RsMV5`BV^Bdi!3+kH#wb7 z%;Smk>BMq-VYywH#sNP}M@B@>g_sL<51=AiOH=&iW#i>#L+grjhEf(%zS1u@MQL)C zY$WHPl!(>=W8@-~b)k|mR-u()+XJx#Vv~j3;>MTt3N?UnBKI>EWhC3q50Z1IwPqL{ zF-1ZKWfWR_^a8hap(v?zrUEe*QUNnm)&R?1v3nJBg$8JqH6#qwigE+G7WP~ymm6GL zvuH_#eJAILHkI?U*#6V9b83Z`mkXE6%CfA4mK~RKMQ4p4Jnx?0F-#WY6_@J^>6THg zLY`7Nj9k1E5a`_~w&QM)1znbEY^|E^CK^*F1(8cCr5T5j@pKZv5;LmZQi&{OMKNK_ ziBdJ-BQF}elamqQ9`F^uzopQHd{tzlVK)-^N z-rNt@9qS#=TW;G8eG#w_Lu^J6QWP;>NyNiAl46wOq)RDsmdbkTyE001o=@~@S1IKH zUpW^EVs6aRTN!9)6AuFxtw~klJZh?_s?bg9sI-6plp!Y7Y|0feLrendOm41()-`6| z6JzD$#|v63Qq*WOidluq*m=Md@aGw=3~NkerLn_=QWfniXwX*SN5?RJpyWGf6&b4J z0G4Kv51q}`guS9_WL*O>Ca8|V8B&0nwaB@&#%SsJ%sCVHOjMen6)!JWN{v_t^OM56 zh_edg0$N8(iLJ*~E<(m?{3rp`N*iIH6c{t(+`0X%IiJ7f{QPTfx0NqnF2tf)_kwm2 zWdnQ27`=15ZmmeAvCgB6mXr#3x^`+yY% ztwbxOlvL&=rd0a;dI9Pm0o?vFei{F0*IA+|7&gDVLpx->PKK%TXDu?4i_u?`2k(0aks|i*@3iquQtII-r zYgWHs09-k2`eS#8Ot}HJ?he`9AiH{~xzH)4FiK&yYS$%)ou=`q0FUEvRJU`GM-ti(Nw75+4fB8h_Z zgM7Tc;GISd9;dwYON;}4^i1Q>n(Ql8W!5dRXE1|iaD&7iyhzVhLHf4#STIH5l4ehu zH7M*Z%0WLECNqGw?72y`oJXn35+d<>WxZWVF*2QmL5Xq47f82mIeB^-~Nhm_P9YD3u25U42eX^ux|lp2bdIEJBfU71A`yML?veV zeyaj)P{tC%!tEvwde%6e&QE;v?KiB8^hpsSDoC$V3@b{VaZYA}(t;dIfp5O~mf!sI zf8)3R@gMx~!}p*9(`*<9haU{p8H|;J#QJd|=YsbG)(D&1O?PN{f?XOo&vSFq%>3KG z{To_q$uoO;;{E&gJUu=0FaP|{P%AHAF8ubl|9KP=sEK{g+^$!&HjLAWd7Mxcv^MN9 zwncp)XK`N@$zwbgw<4<)X(H87iYDhs2<4C=Xx-cPYkQ4IE{gHwnNQEW|L~6aH1ogy z*T3^0|Nc7x=tZ&bk$v0QmWBPc;pdS-jc|?Z`OD#u+MNRDX=a=zhRHCWJ(o)$tP3@D zIj^)Fmy`*)Fb)Ifd8U*i)ua&ElYp)mBif2QJC|}WQI9ND59jWTVkT2#X}M2LW~a;n z*eZrSfX;Y{SdtB0Zo)N@@L|h{2CihOkxQE&=Z;B~(q+!3tn& z@@SOC8H=}?+ifFk8@9P4zSIlr{ypFQ=9v%gp3o+uRl!{X+DZJuwuM6)XuXy=3O}H< zqh|>^duH&tF=>W(@BfJp-~BWE?jxVCkv(VfmMH{MQLTHqa=EO;Alu{3D8b&9BZB0y z-w!wdTW3!p9g-6PK&?NlC~}d0=C~JjQz@yCLxmYgj^=)rnnJsJd0A>xUNSst5y~3kt~iwUDa>w;1lW5j-%nkCfsC6mjQmzPiM`-W1Lc^)v@Vw7dM zZLHUom_~AmY+GjAG9Zim5EH4agcQULrwAZ$$}o%rR$GiVOxoc5z`Cvy*qyV4gDMW0 zrg0XiC?j@Qxrjb>-*>##jH4r$!sU7;=g8?ap>-vujg%AfJhfgy%eu-!y>hobAIAaL z`k=HiV!UzFOw%Bt;v0k*NJ;F%{opZ1H4u>TeqD5(FYJ31d;ZIneNVFZ4~cCHXuUBE zBg0@1Ly&G#GYo_D(Y0{sS_?4*P~sprO(W;0Gax;L`ySXfdG43bpV+od*s&%pgvz?E zt)HnJud6$A)sDBEYl~(Od;W3qjah@27s<*BVQ>4$au0q6=PWTq{@1_#8^8PA_v|rX ztf5q?Hp_8Qj@p3z*g zFy*?15i3P4lFt>R1SlJ&P%RL##6ngXt1a0&`Oa%SDn%enbdT?trip19@q@@r$8n(6 zGijH_bylzQw&1}$r1z>BLv_e!&|=rm8}l5QGi%d`C!&rREr76_t7xmJO00*`y?0f5 zEprv1R;gHL4+i8B3_5q8|BQr59et{q(ikX3hyhh4GjW_I@&hAUijJ9hn^_I2pba>0j-IP--<(n=WrbfC{OyLehHt+8M)EHyEsJu2l2Ns`>^RA? zE2SL0k-!nM-oMAkKFfQAMLWi;NH1$+jJpGuR4`@E?mdi^g7KR9X(H}oa#M50&#!~C z@7H7nTA{2(*NS~miNq8e!(AD2VN4>046(4M%)UpqAu>lu6=F#u_i5V5Ufpe?*;k8z ze}s{9VcR#>ZQ!kT z-`@B!VB<$OdEmXDJ|>a(^=oTsrW}eMiS%E&MSu8sTYl^PYP6qo?@?<~&{C?fXouO# zJs3NsM953X3lt0 zMjX^q3e=j95ZhCoaZaq=wbDF2Ju?jhxds%4VYE1Bh%w3HG%JiwOyerH@!nyK04ZgJ z3DZ_w5kG$X$h40PlV=YiL-KwQgA-%W7_Qd~U%q^4hB5Xyn0r9DZh2ZtNlu#dJ2`H* zE4SON+XEc%l*?dG)Kgpj~_oZTYSqfz_v-Rn4EYLN_@TE`2YU@|9^b?_=S0%FwT)n zMVE@HEyFOy2I!+4^P1K(HZ{g4G>6ARO(JDY8Id8c3nd$2UXbTKJ)Q8w(1PGY3nJFy zz}Emm3W3k-t(jj)xU^LoZ5+iGxw%Ts4fM!_Kq>Xe<~p6uoX=;xm$3A{=$2l&k@Xr_ z*h%{CDB0(g&bElzMgv>M;wlIDP&prqxkq{=2woYiH&i8y@2X|~k{(1^ z+{Y}T>fU=4>M;N4rY*89!l3rtu#^&+L{SB0<^8v9LnHH&QHDzl>|rOTjTogMW3=H` z0wv%3{BE}!`@S=dqqr=>0YC**${gDJ0lUmxWSb(JR;KNfS}0Yd6a6vgr!&9#r!()~ zd(Kb3y*@lePc0LdFA+biXsfVJZnY+~0q>=lkW--|1}?F=xMDn256tIhzWepBB-Ev( z)~olCl44^~lVtAY-1?y9g65oK9Pjyuz3=jE!LK4(f7Rj(N}<{4D-;btSI`t{l|C|M zE6!`Q8`(F-^?D)ez;M3jz5z19wjsS#1*HwzIZP={`s?vN6Qf8~2A>&R7FNv}#%@9~ zRQ6QZV>6s7g@O`BsRIyoOxtqN|077XE=zpu>pT_@#~<&1Yj5*vanbwifAp4bC6B*v zwC(7Nvs_@?1GjBs+C0m)w_9M@BJ-FDW5ro1EU0!)tJdVLyJKW&cHylE^O!sNw?2;V z;b+EQV_WXW#D5(VS%2mL`fD?!fAzIc+2zFSmV zch8t|-cgYSX*X$j{RKCri7{jnTU4@8wpJvNooH;$c$9)7AI^B%h@Ev`>?~#VNOD*%{sdtxku9Qmzx73SSOMp zWyEB}S&OqCD(oq~vMpCy7(?qEXiZHOqcvu5A~|vvYZax;cz2fr4a0!5!c1ucMoUP! zwO(QYlxH0G!%RZ!E+LX2S?N8ql6U7VwFs*s&HKV&h(n_Ew+U-0`&DusAQkC34B_FT zoMcfP;!aF~T1z`vG}>q|Qq}H3*uyYzI?edO5R*Sr8gdrfZ=)^4FcE@OXa9qqai#=ZqoD#Q?vg}*Q*0yx7SiLp5lIw#UW=a|nk<1o@iQw7L1 zw%$t7GUrmUrr@0907^ex%c{$o9yviXV}Q~o5ShW`7*u^VinW?y@RTan?6SXm_(n4Y zs9)na-a9ypn8O{i>?C}JTZ2luNlTt!uB}|U4kgEW;nxr35X-v_w!?jF=s<|Ah#-6>E zW%buSLe7=OIZsuET%`%v7!5^9zuqqMz@vH0;Dw1TQ4>mj^_q{{{-YkAc3$)dl0HfI z{x<<~MsnP?KyE?d!v7Vt5%ymhOT{$eN1;s>MS>sjlq&sg+rAUR zN~sB@1q_X&<8+!BMtOgUM^jiMC?usQY-!2VTEw)ameTp#n;w3h3DwCV}N zU5oT4%6BFbODX(ls?Ka_0XHyA1M@hdN60b4n~S#eueFRvMeAh~Gb8ORCOMpUxFO+N zg*3Xv;4(v-Uq^45yk(0bk=&yt1c~7&?OLcoTJQP_M{#_X${$f&ezh={{e0Y2@Av#9 zVB_Jbf6jQbz$+EDm{_)*wS%=au&j}FjjUs0oFqV7Y0$Q|MOsGPI~RmcMhz z@aK>E^EqpO{kQ)+{s#WW0o(D=pOQjWS#KQfi23d!+5g^6H-uFxO%e&TKHvI?n!fVB zuf{Pi+~>j0(n}B9{UQDLmZtLfBD~g0KK%77^UeX%+BW`J4q8Rk(%c|BC>6882H4u# z@c?Y?zC9&UiKN`Zup40O`>R&jHm%hWapSDPTZ^|As}0r|?Bm4Q%@b;^M-b{bjVP^1 zIURp{l=Jky8l@y_YzrH;K->#fsRr0+J3CTR6-|3hc8K;To^Gpbq6wR?P4{>J?1}J#1DH&prgDBBKxwO)iF1f}3DQ zYt892VznZtNUaJ#42**~!&&R`&ah0o$e|RiH$cFegdZo2sZ7I(aT-L{6Lzc-siUF_ zQf~(URl;nk(mx~CtAUus)l*ynEh!e(EwFAk_I*7TueOJl+luw(SXiFVC*FT}M@%~* z?kv}Z^|nFHjg@rxVdV3t&ur@r>m1(O#+ccbXEx!zm_N+(EJiZ(#QA(ao7jCzeah#Z^xfKtr?56@LZ7j=n6dDdAjx5y==}&YGJi6AW6-ZG`A!=htQ;yAG zKsAE`f5a*5&AIRBwQ73fr{^=%JRzaunL=&Ww^B&Rt%+Cb0;=MW9uT?7&pB&hJUiSNwF;pw`Dol zBGcHyd7e4VGjRtR5PEC0@fhWBT&T2!vU~6GO>XMFhZm{p4U<2dcthMJ!k{PQ)GUC+ zSSpH?ItbNB=3K=(j~_;qif9u=&h|9poFe7Gwu^&j2s@RCbp~rBwEF$~C(!n24A-qd zAQ$06jC%uYGEYnOQvh$5%XfC|5h&jcM?|8joBUe-R@?ET4hCFaRxV^!WtMoOy3F`I zFpU#a9jRFYu3ulb#c%}Gu08!)t`P$gE5OaRYNmG?-vOI549+q-$LJkntc=kx2E%3~ zAXZbT$_O@-+5vwgMEmncUrfI(J^uwq0rr$x_joXC>lWFz#J0tD%Tlm3S}O6#+@=ap z6spK~q5hs1-@lAs#y|LYWSH)helNT|8jbYpdo%ZonG}0LnS(Ww*Zjjlw|etSrMWcL zdcd#;K|`wpsaLhSu5$R%w!MA*ul)Vd@a(NCWIFoJ?itV}*VlmUp@%ItsioMDrUca!y-FCTCcGlS=+e_qpcRTC;_-@lr1+5HLS#ht6 zFpeVey3~c7R%zA?6^zDehcg=Qv{dSkyr>;(HO0zRP#eWC8lIj;mUUoVJ=%JV^Gt)d zooO{uoMDT9CB!!)n4cbU>c8I%Faj}#t{Xf=8o>x_cT%t5hSJ>iCxhYZ< zO0!a%lcU2819tG@I0nK-wtW{uAUKO@LD(AA$i6NN%h$zMJ|aH1N*vAOB5*>k||}3=wHn=P*Orw&peJ8;= zC2_dFx;+2}bubyzWLqGy zX^TsJKjBKIHX1*riYZcj=(3)ig>^&Gnr$m#j{+o&Vi<)rRz_2@EUjC={Xy+(YlZPr zN*L|YGma90ptOV}OCxHNzCmLq4Jd=v16m6!A)rGhoMG@7t0l}kMTSwNi{5FhQ7vvD zOaGYGggvouD`Ai1hYFd~?vVAC7VBWGN9%aZq7~Tpz~ypl6I&t2N{J$W6lcPGOn7j& z=|AR;3c1Sbr^a0OqEH9f!!X<@(ALbXjl%fha7XQctu&ff86~kEMm33~#VL0@|80=- zV?Njc>XQQ9Kl?)jLAzk|W9i-ViRWjLQ>HBahQiL?WtTmNuSYfX`v8=c-ZIj*d)zTz08LdDWd(q$BK>+*6_#z~^OrC9@dNYx#IkPOZkre@-4eMdhURVx5!HgP zOHpWDu(tKV>N}ux)}l0Q`$|<3XkL=UDBPB-NXc^~h8=1_wPtBWI~KJt!(Ey2SQv!6 z3`hFsdcRs{T?Ak`Yo+kzhZYB81lSo34u*N;>HUdm5;=9vnfMjc5mY&xHqj4@kq#J- z9KlR>7T<1zvl5=|<=@p6hIaqpEU6S(w5UpNX;b&*!o%{QmmMFfzW*CX-={xW$nN9! ztfxvT>@jk=t&D@`dfr&Kz;)S~2G2Z=IIG$@2il1IQAs5TRa#N!fz^I2;`}`^ZoiCQ z#y`qfJzW9I8=<`4?0@qfagohlqdMqtv zZY_6l#e=xvxZ~Bke+|ermD!{FWvLG?)#=`s7Gr(|*p7a+1IXori3`nWB$eLdmc$4y zCy5e*rsff#=G(Q`T7zrSNJEoEc2L#%yeaue6a=XXz>pP#WVbK5sS z;mgYxreS7m{arCe zo}Qj~ets_wqpd=bsic^xWhduAh>B&s2?IIL%=1Zl;f$tvQLt_f>qKt1?|WmIED{YM z(kW0F9w>r5-;h#Xp~ zW#+i`Nq*l0DSf^hilj=3_lf^;bTB6QjE%9XGMDcmNRL}%@%ybaQGF5&ArSU}HHOKL zch^iU75$V`llx{Nm~_wjGMH*5zwH6AJu-if7p@p1MayfH*7qcmi4Kru5*@we*T4Rb z_wSzw`zrZ&$s7&Gy&%?u$A@7!3S`z=P+*)vyOtTLVBJ^Z9$7ajj%lY4gClD#$!2uP zCZdtA*SfBU9NAh+ zrEs~vfD$*$ecRaAh1=~)N`aU{>zgfTCB+AYZooy3oqpkcRB`lue8~DL)Rti>MG?8C zSf`m!B9k7+vB@JVSdE!1ejb=lGvnYf)>3n3U*FjJEA{%OA1WtWNz6*CY~}{oTmxjm zSw?5soya1G&;VPLO2(WhsSuj{r#`;ttIzP$3x&U@ArTpw+qyF^8`s;)t%J3}^K=T> z2H31snAQlFl^Aj9Qa~xH)~^h;f#rlPvO6T+WKH1#J<%Z#&t7QblrV zTBYAwD;Dvi7#(P3*|*5$awX@AbDm`pi}!vJ6SAYp=d3KYy>}Q5xk_)B(al^U213|S zb;c;jDYB*;pFb_!ZX3o{j47yVqSPSfCC#PAxdG=5r_;#xvQtVxLd;bI2X_W>-*>Dx zq!ifW*32ZN7fZHNn2ByWqP3tE{`EtpWn3%?qar8{n!09wKchY+xa%(-o zISWY7S}m2hCvJ5`ETd%`h5<^dVw!^Nd)Evcaw)CHN~AmOOMRtJ)=HtRYNji4JeJgr zB8n_hTfdD`A`Ps{G$y2Fekp}EmSGT(qqJ%Eu)4`Nd&Nj{4r_BhEv2&W8>MD(`qYM; zW#KM=8A_b|#59YPktQWgwGylJcxp6>LTVMP3=|DmO;N&p z=~Bp9j8r;s>+*&^x#e7r=z}c>a*oG@*IA`u7!Jq4N3($tBXJLCt(oST9?slBm0SoU zR%954qYq6h)tEI%xdm3%BsRLO$4eC&8?Mn9Y%OT+4By*D<0_@*#?DDCQ5j*gl~$6S=Pjd_p5kE| zh%p_eJjTccX%CUhb!FWmDZ?HTw{;^&C2V04sdCAcoHBc<#E_cf=ftj~$UCYye8s#F z@`g4J>wIHigMi^S-&TZOGe$QVBhB!}G=@4I+unQ4Y0YEyEZh?Hagp6 zlH%MoI7^5v|FQM5RT?1t2OSkiwX(%1Ebg*#T{fn{a~j2z$y$YTiabbRPdDaN@`Xy1 zM&8f=UqIR~zH&?(r?EA&-}?~ueLof%eNm;g zZjJFf%PRj$xbMKbr+1uAPiU>BhbKXfps*M%z^x`^@mMm(NWX`GB?lO4RaoO0{KRQ~ z=H2r*d_R6hDe1QgVHcM;V+FP5!r%hlZCqZy@bdBliiFk~rLJhDShpQ*BGYu@>FFK0 zYGRT;y%-ZIR&wernx|@o(e+*-A4jHnKC0)($dVytsxV@;WVUU?+U|x6qc zbDpJd4K%l9Yqs|hYaKD9X8kVmFS)p7K!Dod9OE=#v{?BIu&IrO*x0vC7#XA3x0P*6 z{O51K@N!uhM}x72EnJ9cJwT8E0&vc7I!$~wp)s)Hw3u_I#DWSHWnc&a7cBd}3Rth; zhp`!nxMuKDaLxnjxbJqmv8}tfBMzQgBRK_}JM-?{^I<-6yDfyUwQcK*M8p7NaO_)P zUANYgCoZ5l7luKMNph}uH=;clYiKcm#28tZtuX)!XFbC(9=&lXWt=rAW!iqx4Lpd& zcWTUMUwk_!fW$bBaw4PafbBGlIP35Qtlx!lr}ecpnPASDTi97{1@Fb>F2sn|ifIxv zo^@T3^Hn5bmzRxgTMyS(=MBXe(rw4=n)mOYIh~$3oo9yDd$y%OteIFl5Qa#l8bvOZ zqyTHsMp3jPmW(cjk}EGSFN6?VkKw6J*tr!GD&r`9hm;Fp-49SQjwACt^Yrw@`FuWH z6FcaM4gC9Yy>TWSeB(3+?>S4u}LFQ9B!MbL}FvtQjNk~S$zOD zgT)q$x1tsRjvlnfN&DVc*2tIxuxV;mQfNXX45po5Aq3WS<>@qGy$353xiLA%X>eSw3tCsKt@uGp=d3npQ=ynv za=!z%$D+wEpzW9O%lNMwU+>#`!!|XbR_bFrOg`AP&M?)?;U=j&WAVG9RxraMiQKjg?+3~Fa!#zoQ$!n$aYo2P#VdEnM=4Ry z6%s4*-fIFm7S?4G*Tw==g|n{7AwgrBj7=8e(zKYUMV!JEVp|?VWnB^e{Zorrg&*=XdLBb>LX3yrHRZM#LmVS@vsahCtBrB6jDBF6N1jhJT3hyz(ON=v z#dS`yw(fl&BE5ThJ~Ivznu^uZZ$>S|D2Jo54y{`AqPHlj7zq?b*n7p_9{OZ)X%yM1 zm|fU=m799V?NXB7z24X7M{|Jnn8VQ%)05tl$|#b^tBfV=k!9JWPjMUpjrYT0qmPnm zLaCWOtSDW9!m=(b%hH_Z)FGMD+TrX(PL)ztgvB$6AxS;fOv283X-qZxA&^}r5n)=o z@rZ4b$&nZn3Vjq1Q2oS}=|GOp+L%L!HDc=0nWww9T7X+iB0*`*IL}}#VGD#5As1?n zP@vXAOaY?}<0uZA!c0gNCMT)v5ah8vKRq7Csnncz^!myZ(P?E?Hy14Lz6xh zOd0TKTu}@~HH%tdPm~C(n?g;zBvTZ2vOCooZNO@g5pxqml6^lWT#0dz-+ND62br~2 zmQ@~~+9Vg--#UZaL1C@+kYeZDGUk+#J}xA)E;lKp^f?JbilSNmXKIppr^gCB_Rq+< zaqrEnRRB7rqMJOlR{1_-5Jpb}YLLR!aSS^~-GEhJ zyvw;cjwA2hJu{3go313bZ9zMYUk6I@!gz;F+=9fbsMp`ASjhKPLzhLiD|&5)GuEI= z3nz6B=Mv6md~^&xF?c5qpaYD#GUY51-W1tm#KerQBA-#ma-l5D~bKvurjq5FPx$MMP ziA_S+?ZrzDhoDy49@O!L_U6iM+qmAYM>W0ohghQ-{D5;BYh{sky4AQ(uO22H6ED2)Nr_w75HCkv@0akDELrNm%i-4^zjjrk-}#?DZcw3Cgn zE_N_1%Z-fhj!0fz14Itffb9944jX^@F6C4!?Iah8q_}W8=MLs1 zr9`d*E=&Uh71+a0Ou6+uS;lF?4Fjv)(A!4ZgM>3v4uGsQoX;nwX#&JDS0V%o+tvW8 z9`J)ZBx$N^y(vvjEG*i#iB$LVa$^ZQ-~8%Zp5MLWdR@3)HwJA{Zop{S2NFCUDMC@A zQ~~ng?3r_6S=I*ZwE%t%%WdWIawYCNao-O{I;F(rB6)mWf;~+W`!38#Oj#zrvQj>O zW*Q9B&t$Kh@&+ zmp*#_*!TU*;+sEzYyRBN|25|2uYLdD(hTrZ43rdM?tNY2KU^ut-#d_lL)i?CX}f2z z#V9>ny%<)r7&7T5aa2lu^}G4nK2mRPf0^m@P4C+Scy7|diFvCrrn~y zE4%~~+!?xi&Z?Nsp_>}T2&v+o!#Ul|MYI68N5E!;anm$Mer*h;3VPi3U3##JWRfWj zs7j0hV>PGKiD4L<`G95cUh->NW>arsPa(2v3GVIHR#GBIxs{Z~`#4u>zK6xh!mu$r zfK?W4JgqLwwpnscxWVGQA?N#|L`-NDAr)@RPR@~GPz(bYGcr%l_#vZA#QMqz4Eu^( zK`CL#!j=iK;H*cFnp8Lr;ohTCa&7qvvY;(R`ewADu^g?^j4Wn*wv@37MK_WtEPKSd zfN_qR6PN4C^&&k&wX{ZfLksb(jZLW{9n2fK1eBHqpdUR&NpH}HZ@yukXT&x%u5E?n zX(=1aF<2`xibJ6);FV(Z9zWOy;4H>^w03A^i6OG)mE7VXq#sM1_)-oGqv6;8^q%+c z-*LU(xL&SYF4EIOGgy)SJ;-hHkTxA**|b({>n;tfPJ)<86_ph_>xY{{7rEt>h*c(> zUPiB_xm)TUaIa7*w~4oL2~{=53Y<68Y{;=Oj-?*Gu(~sK)Pt4Y_dss4)LJUF6jF@r z>qe>NI0kfE*c+{nN!K}xA3e?+v@wJfST_lqcY{S4$!_V@v1Bq?gRV_x&~8d8Y!({g>B5C zvhN9J4aF!@l4ysNDq&CUA|>~SAY}xlAEYNm8n8>wT&V%&fr_#qS5kQ58k3s?CVC@D!1E>l!Hhy(cG?!C=0aovX)dtWno`S zBFkYk(s~*xDBWeSic*zWLR*V+5^k?!!Nh_M3F}13FnGfd+D#iqBX<9jcWlv#ZF4Dy zo7sJ3Qt#Ihpf|s_?!O0yOdWEg{+Oc|;Bqzrs@@A_V7ACX5#Lj=WC4I z*M9EVN3j%cTjaXzTyHz0_Y6Z~S`zCd5jVyuTrrfEi>R6`=vBWcT^=b5z}}4i_}T9) z?9YscVsg9V)pq{*0OSwhA-}$=Y~HoUt9PgSD)y|@9}fgPJR68 zPhe6jU*GdT#~6M6{-65%Ux#3SiTm5tjr*B;AFmlUbv#u7ihBLHj$G=G9{y^VzJB-n z6CQ0hz6vaj5rs}Ickrg9|4e$s+E!GFC&~q4f;|?tJ+lQ-dZk2DTZkE;qBckHa;zJU zPw|x+TBFv`=tJ$L+uWy$^a<R(0RMXz3^Tu;^5suS&{834V;PG zG2JDSO&yY3uUcwmBB{wi`(p$X}+9+*%KyX)KP#`z9AH z(!;gwS4v$eIY>{-X~fwPOvG8ozy5!I!_)bEFdAF95@O^$80LAx?LuAWY|#eZJ&!!U z8<=K?v6ahZ<Q#;28zvg!f^NNZVp5QC4(5}`+mUe`Q5b49?3)B; zr&NhSGBR>WjFSW#QzgtW=R_bKj(_t00@%c0qn+!ew73D0S<0eN0Ep~QO${N|s&<=_9~x8$<$a*6Ew zhIcbsIZ~{`tTeVl_aX}dsMgzxs+IHk%s35LEWU!;Azu@9&9GMpl^QbJy0h*9YaCkJ zR*;Y?d2JG9&}i-C0;Kv9NZ8nE9ypyx7NyBi7RWgZC>aLV`Y^Rjhz}ZY8Yr;ZP?bi3 zL~*3Vz6%SbwPG44#%V$+D7oMV&p1!ar-^AE$tAO{3x(3mNJJu;+xHxOCOQGRMt5gG zCz4KRxq|0rUXm$f1|>Nt^Ei`pW{oR(i>LyoEgnl1XUaY8)L2j`bPa?pOC*SD7elSM zEVm~Al#un&836>wW0he%&5ZLTY#v~}Ln$v=e<>b$iQVwYq)bAX#keQw%_&4t&sZn1HqIMyhIEC&W(I2* zY|m%&j4`su#IAe8eMQleq8}DkuNGPN+@RXblHM*%e-0jeZ4vu(&%OWrcG3E%9jb31 z{G*5V*DbY@N@0zW+q!dIHs*0;93#^h8P|yQ2I~uMq-C*zKBQJXE~H7OXwuc=Gxc1) z{$c(Az{cZ(@WGGxW~Ih{{Ho2_VJwlse;VcKG~0euWGrM zin}E8)&Kh3b+`J@8B(sqRM>-%9We>$sXgOFH}QTi&ODx<>JhNL{#hX`pHj5U#tO}e zSbEleJP+K9KX5N7x5C#0R(|Vp`N*Q(d(ZA`l;dxui0m_^7Jyw2RiQlY4%kYqZ4FU{ zRRf#`Yo%{(XnoR;J!{rloVgcc55T5+1d_sb7O0fU9!1vSy^)MFqZtN&EKqN^8|x~T z{8}4^A(OLhZeD?HTUghHJ#3Vku+E~D6Y~d3b3tj$Krc8HS$w5fs4An{g+AAUjusGx zO;yvJ84VceHJDFlj8h_sjO8dtYHDLFBoH}exZXDG2xgG}qc~!#UMXSwa!$A=hsq^OmQ~w6=f!PP8!hy5)4wJPAxY00N@!y-vXFif zZJ-v>_or0Isotqns~IPUvm?f6S;&Nq5O+|OZCj+*sY)K0>X}8V+44JioswlybUF>3 z05L(%zD@($BytIq9LOoMuYq+5^;X_3Ruw82iWY`S+*2VYStuGSr6ytfXteh|;J3er zA3djeU~mIgYgEagGOE^AH8OZJFb*RnOEiE|P*S1f)PRJ+4GLomAuO!xMF1nRxR!oG zjZunJCC{T&IR|m{y%tN}M?NyfsEU zOYc{kg9hg$qplQ&abTKf+~9-()|zpe+UKsM99ll#>qhFwDp=Q)*IFe`q`9*0aX;$O zGI1)DHjHi{3`r_;O`2JOT$@u=Nz(6HkpNKz%4lLvn3V9-gdayQ>GnCRU zVBKkJkD>K=DwcI++cr{47;AA_&fmC4;T&RS` zUI^p4ZM1wsF$YO8iF<1i$+0scp$suJw@7h+)W+bNq&7G9t&(NFXgz&7CrT2dBCVts z5(-ueptD9dm4(76h1DVlsYoF$r;O2^=^B{Fnfd&L^@G47C6Bkp;>^9*??)?@$A4ut z@aku!HQHI6cO>s{-s5~|b9u)3iuZ*fw!XIH8B)TBfO8QWMM_IM_S;eYl@Ib?HGXcv z`p1m|N7Z@T_XgT_hQUgo_T;fnVVuT}wwb$VXmVYx@0IRX3_*Rs*uRWl#$R;&y&hP1 zhUgV`{|j!;j{w?nd+2BDzn9vikhS%^-$Biz8Kn4vm52A>xUR}fbZ7U~n~izA?~g49 zyzPfQFb8+Q)|s=nMk8Iy*bCuz2Cfj=eJQ8Ae?^L~p4(lXkG$RH_~?#cYN$g}*o8GmDgzg_JW?CC*}l162ueZw3KT z`pr}!mPD!rt8`mX8FCgDCnu?N?3*+)I?o~5diVUq)AN~>6aVoa|H0+u0*E})eE&O^ zbv^Q}jJ4Pzr(n(rtt(DL(c*G(wdF>uh+1of@ge|) zch66J_fOwqET9$Z8d#T|m(L5etc=sZ={!?vYW-B=Z0Nkf`IAH&oF>+FXSwYplQE{B zFn5MUdc{2N-+$oSUww;GnM!0BEJ{~Wtki1o&NB`t)-^O{SU{gJb)J+W%d#A1IiLu+ z_q?bBU}&wG=ZQT)zU?U0Tr?3WWKNYm#kTMeHq=?mG@W>U_m0!a<9$WdNJ>F0`ijLG zhf$Wn4m_XE3{EoUa!TB;8@VllrC%+v?KfUtKJxkVM^dtgJ8C7B%;-GcYEqO!M{VEp zJqt@Uwj>jDVqbRlWrt7*b{F%En8_7V%a*G#k#Yr<1pqrk$x<;g+Bd8Ad^iD0u3?~- z!n*COTS8@zDq~{|DruKo!=c4BD3ruOSj#ZzBb%hlZhKZAa7M-LJ_AHt5(B8Th7NLp1&HbP<<-Rqth zt?)*|!jBKzHrq5)id4ZGi}#js7?|dPr{`xreDf>Dd2aGNk&P($v913rhV8hD(oj`1 z){*yCx*pl1#!6w(IoECp=ZXNg&_Yfh0=5Td*<2!(LM*+iD}^p<7e&>@VgTO zAOmP~$YlkbHRipP_EibHCME+9pSPJG{M`5{p!b$}{A-P`xm_ObtKNe5Kla7n9vgqc z__Oi)&pr7sj3EA$kMMKjt@r!?mhtd?{luyK^>0)?JVd>E@T)-RuRZxVhkoYs{D>jt z!BphOu8^>{sp%47x8~O4pcI?&tU1a~j64!e8Mjb)g zbT;n(#Qr+v0Z7&d0~L`mHs#z~z?PairDU%kB2j|Ex(0671+5jaH8$R^8_P|c^md=|{)Bf~WNXS`j7JZS z)BMEwG|5G2qL7|zBkqEUNiSapL6(0i-o`Spqp+tiD8F0 z{ngf|wBx;Hn#Sf5nCQKJA?#?Q2tle85)ly&!-{UsFpi@bm{=>-c3Ux4@$@v~y(5O^ zc&JCL9r^tEg$)nC1ze{V_>(=R9G&bYt8q zwBEfG1KU=JIigKMDftXZi9C(QXlt$TuJ>bF!Y<#bv+};%7C;r&B@jX(#Y)NI@TZMy zl2fT1S!1OhrKGpZI(;mDYHe9_6)2Uk@1zi#{7{0sjS>+;&PjSqRKZy#ud6gDF*d0s zQHz+6C?%5-N`mKU6u#Fdym=zVotQS6A6h7KOraGe9;|iS`Puh>t(w|;wZwh)9@4F~ zZu65EwG<68N0!^I^>liy)flbV_KoZ1Lal{i^oKw~t0qNh4bURdjKt8TrNSf|t*Ayf zA%M6d8gKD=z)vGZgB={>V~7Rdba}6fMAX-**AISy)`x&2(}`RT%v! zR`u(~p7-NInqneHakf-#&U41H$IgJs94M})nZ)Z#Vh3i*C{*cENRa|-{pesx%YGC^ zM9@pZucV-VjaqQ@djz5o3Cj)1pJRezV? zckH}%hWzTSbat&7Ni|7e2vM$4%^k6|mdTRiXc~L{*?tPJJvukv`*G{5WB98Dn76Xr z2W3`n*|Bg3rlsYlbyY}u1K4^Pc0QQ6#-=r=?ytE?9&?t~7$wDKkv(dxRu4eU9BUiX zd(xYMS_fz9Sc@uj^KY=ZRb;i63y)l|cS6W4%SJAV%jKo@o`^&e1iUQ@_MpUuT@}9h z=9$xZCWOScM{c*3WnEAh$V&QQlxCO*jB?_Ls1!vNl&zefEa&%@)7def2lk-ZH;C~Q zpFV$qeIwTkRS%>xG)sDqx027aZ#$uaX~0t?g$XrU{NQ=Hec{u8eiA?tBI7V~n$Aqa ziP4`9z*h5r@af}c0H$$Z*;m%v3N=f!yy**!KnRkXq>2QC?m;ZPt-ZRfL??1dl zE5*LATrMws`YdjLDMU)BLTQ82PGqcPLJ;7-te|bg4~qHZ z@J5q!f)Xf7wMj3dRFz(xV%Y}KK|3!e>2lkJ(by{`TT&F}b@T()jBLwF+(Wa7wT19U0InC;SQLYUil!Z z27`x3X5G5i%9LFUC?&l}If)pC4*~0)#H&4MEhY71YAEf+ zKTy%>$c<8Br+U@i1gpBgS-^RX^P01N;XJ)?yyETif(9{ z9HSC`eePBj3IVPPC4wTQ(2VfJ#=IJ2{0-y=OaXOu-wej{QAlDex0kGZ0PKL_m5ljy= z?6FL05(ULg^-7uQi3Z_v7^9(8S}hWOD52KGEd7(tx!!}Qu--9+GcTWB_?LhABhSxI z%v0d$<(VIU`Vnm`uWzr^);P~IwN$?R`s+8r$Pl)WUJ1P?FZK&R%(Q#*Q1@}bIdd@5 zwo+kpMJUVtH3Ux%Aw%nN^0y4T_iS)VbfNea}$LIU_oPT8X(K<8Xm@gVX zzdtwMe826j(*TG4KlZG>2W$6Nsl6Az#>@#??KuS z)RTUGrHA0ky~5U2tffax`qaeJE2~6pvU3fQdk2Nq9<413gS8Em@3f{1)@v?LGu~TL zmYsJ_dWLEi>V))3M5=9gt7O2|nx@5!Rt&NO#z-UoxFXhq4+?E7%0z0DW=H9vF~k}v zN+_KGyBAo_+-`|lW?IX9y?*8E^=p@N7phC}A~AlRFXUL*S~u^mg&ZT9MoODh7McM@ zIdue^P3T9P1n}FoVvGVTMxVHxXHN5k)pBcTEvD3`IiOV)$@f}%mT~mS8C0jK(nO*= zccnvTCC4(P?49#iBSICWXi}^!w?xk1y~Eic%6BN%HPWh3GHX>>>zR~Dep{!=Ins)! zBrrl8cm+Qr zk<#Pvb2rr$neex_xBI|?@O*7AJEtVRU9A}u(m(OjPd{?KuDzOAfh-l-IgpcnpqPo8 zpbRdxsY8ZWs>>4U>B9g6+IHn0Cnkup(}k48(O%o!MP~xuJ28qcjcr?d4^b8>DXr6N zEvWfg+Z(kNa*d!G>rE0hITksd(fr(jV9|x5E7ew-ky%J7>9?GwY4_25nCx2H zD_~lSBBFqNy;riGldPX42)3ODsC7lDvikwXD6ESR0+-8W2Zkftc-*e)jnl^He$NW{ zRa!F|-07AvBZE5Rq?OUVe@sNNQqEkL8`fKVaH7b$Eua+Zc0*}J!;3JIeH=%QN@3DF z*DGvCGgc+nwcGkZt#U7vLQWZ%94=X0thik8$>O6WBu7Y|;1g381>l&gG~lO79#yrD z2OHcuJcHuI`|8^N{D4mS4SO(z%UwSuK?DaOak81C>dcX63lgxUUE5^T%FR|SkOn_P&HMjfxlm)ESu3Rn8aDN@R z--^d1%n`61Jx~WwskL@S3^YB~M_J%TnxUssQfl)_Haj6xLe zly20LQ9T1Ga@8Z)Md)SP;#}w@J;UX4;?ob$oG*b~qEwA~!`?j4*t283Mc&FnjET3` zH%whaDOD;x%2duz9#jEcu^zOk``EXxD=A*F+Tv|*a4(4% zuf+Jqx=gIgiLI{05;>pFJYAj$e(s_do_U_Qm9-0r2oT%0mA7RP1sx;k*n6Sf#4179 z@J%aOOuyq6F;>JPyfggx!zV%rY;h&0DE&-SPNzu%;#IS%gi4jH6{<<4NqUt8WYnT4 z1w_`^V~tb`obv?l$tJUUsaV8Vd3#&XdS#v`e){PrPNxgo7P(&E$Z0{*IL%L-<`b8v zPZ;|`%A!!YTpJ}ttbIjcX+$d0_acg4UOeiQBIm+wyHRW6@_c4K%``M>sMsmT%gZNz z_~8@ly72aP6FQ@Dm`)Wuoi6CY z)tF~VjL1ZwJLr*0U+`9{X+{hE%Ns6FCoY#0U%!0iYgswX6Q|SZF4b!cMq55Tz3{^i zpSlsV^uUGSL1j?6)5rotiLjK$^(K`jXZ`*>4}dYi#Hg&LlvtLfE3LJjJQ7bnYfaxD z0kYc?sZGR$!W0N$5>G@slwO72S}5Y#XYaWLxY>8ID zprE#H=OEO?(@DG$@5)wX2fexrwaC4zdXJ=M>gUF~o{VaRltpAC1TUV7weG!bU%!6k z?d=U?#3QW~>2n)~=%p)V4TUVNHQI`~yNJAi>&yx%JE?t!9rtLdGUJDN#u!D68(+SD z=I!>z+qDDSmU&%X0cive-eDAYYrCTE2TP}esg9TijaiI9dnFS=R_Z{BlyT2=waAJ~ zaxaG~HQ;$gRGu?=ZGcz8$;f3WO<#(~;%q)qP8$8WFZH#PwGHGj1I z@BeLY{@*j+5342D#+ox`UGc#(t%1|JF)bVO5;?6A7o^$V7=_VwSG8>&tm)o^+jcRM zN0`pVQrXyhcyFp|7=7+!itG_{q{A*0hzrFH*+xLHW{l7zJ{r=V; zm+yl1zp_gCO%LJ+6`$YQ&bzJd|Go!Q<4L{)j1PqWdzMvp{Q&0rH^y_R-q)Vm2WRZv z?jFI}M^&}=y=-@7*Sj(F@F&Yje(yRD`)^LXAIW4&O#dAYL9^JSYb1V z?`z$UUBU3Z);;-YW%9NdEx}^xq93XhtZf*pcLmK>6<~I=+SWw&o1J$)F65op+1uk# zs%O7bL^XwKMg$morADF2sj{t!(l&BisMS!afo7Pd0J@@d>4SWwkZCos+*WS4mD6-W zPl{SH^{@}yw(&|qd9Ypt3{IyLs+rvjYOyP~+f6d~Ib)0^1W#49E5a0};COj@BB#vP z*Me@~jJw}#Jy_GKbvk1qt{WN=l_;qr^qPT2%N5nY8H+lJa-(Vnlttl)@qW{^CV|{M zpE%8v7|U8m2$M+guOhNxw3X^y6YA0Ba^~gviR<+%wM4Ad()jNUVRD?$6MoXfsJYz? zaownOLjZiIT`Kkrc&U|C3R}w56=I3x5^2VeN+Yg`Qd;-&5ZU%xB(RK80RQQ9?!p+V zd#u^rSaF=o0h;G|=K1-Vx3@RGe*L-+9x=jgsl5{5X-)TXd#`9H)q4kLwwH@|t(Ci% zSgZZMH*$mC2cg`3l*Fe^)q8qZByB6sb?bnXKs6Civ0`sga+3;iRWvn(IYvQ8IMM62 zkW*$l%~&gdt>j8=qIfwu5!TQ~z(9MZGO>~{8kCjmqP61b`6RSg)mYXmjUv^t z?vp4KFU>p$F<&o51V*&DbzPSm+9Fj4(=b-5!OkkI25TDDR3K7v7s2s%Px{IIo>-Pm zDw|n)*u->OY$eW@GbJ~v)}_L-h|#m^gOf4lVE`TX!l?Xg+t#aZ4yO&u$#thIjMmb2 z0TFuTvSjfTYGxM8l}Kqxf_aTp&^k!kRuNvY#tP`M(mR*e zm9`aH7L{2_-DR6qm1=xZiB=>rkYj{a2|A#h^k=rxq>>FiV<})lp(&|Qa}gVek%82M z!khMqbn)smIZnvFwd2HyuH)IrT zttzyPS*l^Q!`eGoQ}y1%_DFg<{N6hA2KZagNu$TRTJEd=%;o(#egJGA$dUi8%YWA1 z|K7dvTY&9<_vNAIx-TEm`TkZ4?-7jFChUUYEdTAA^t(47vN?R~5Agff>b=OwM__Fz zZ4Vs^k++uwmH1zZqHrzm?)!HDd9YVLI&WiNKJ05#$MIl%cDy~3w^ErpZo5_v$MSeQ zqk?t>X-AdE2c^iGNu>j}B7kk|fL7hp)!5xXO(>AP4WnDs*p8$012B8+Q+t0tL{0he zJqrcrbvMD5i80p=oiZVa5Qudetu(bjt-UUZp_I(BF1%fhRAQ>g`-^{*R3>tg3kr|u zw&>Emc05&y|5A*Zx3>s-qv=ti)EIM;z}|qim6W6O=j04*Qhj;7p_(X}wXR^c)0|pn zSr%qDi^|wMGtV>YEpofvy2wW5_PX%)^;NRoUIMTuedc<-^5yjla|rzL#~(#P`?gS( z!Ffk5O#&5?L?b=Gic92|pMT-$=^~Ye3MJ;Q7%BZqjfPQ%aFI%9%NmqLE6=tiQWTK} ztvyq4TrL;RrxT?%thP+^Ov#yPSxEhOz4s_BVCUu26F>a;f>If+i%gV8;oQtLdFE3f zOcte*^y8I6jB%$f(vf~?1q#HhQBi1Bwu)C(1zz74uD4YJ%L+A1pc1AV-Z`lP6%nNg zlj|j8xzUHW#n^U?ajy)VPAC5Kr$6!MKmVEA?Y4`Uv?g@j)9K9Rav_A7Da>eP1UwW0 zh|XGm{P9O}r)n;XP`VnmtMQ1fz#gP0QOCSZ9c7BPH>F>ucCzw-3_%;ofnn8Z5Z_WDLz5^uMK*S9ORC2C8Y&VkEi;&ht% z@yAcZEwd~uDQ4D16eLA#$LzGb0nS>x3)hSRR?Or@;9~T5l~hP2?*47LBnb?yVY_X7 z<%@u7Jq)^Gj44oAhg5U$3OCh&P;Z%rCU!dWNP+P8%iH~#YT&kvK_qj{=`+VpAvz^Um$gc$vRQeB`$dfBYAz1miBsfc2v zHF#?dN|BD}D#15`PXyl+B3)8?6gY;l_CxjTf6?U_aAwKqv82pxOI+8;yhP?Tv8+j? z{+*R`<_p#qj^J5ww*t|viw`wXOQV0Hw)@Y2^M3AM`LC_A?E$$u_(A<$yU;zY{*LeN zpm7N7eDs;@H1&kisMEDhQKq4q_@k=#YifOb7vAhQ|O+CVw<64LJ8Senv*#FTcwF9rHq*tHMxVa4^61^pMn3?y(ZhCs zPxbR*YfETdu}(a#jJ2Fjo|FpKf(wRup8BK+IW^WLO68%}`p=6`_ zZ8JEsF-ES}D>?S^CkfiZvMk(|r3b}QjVV=B<0kJgT9Lb0#wZEXAmzfgMz$CQ)M`ad zjgrJ)Zd(#*6QFimuF$GTLVM{s@y=qMM`37HL^G&X6ac#~oz_Z%tuAlhn#McN`En6} zQ6lSh!#OdPc3zYMbJ^IoZg3q;H>fpe?W9@W8^i;;H&)iXXW6w@;t_@IG@V}U=(yBU zt)X;5KZHolrSsm3;;Xoc$bV;`o3$4t+t2#m_gkRJ~r?C-TEnJA?k z-ktDn!kBz+g?LV?KruZ@%hIKa9u@gNL%SAs@2k(ScObepfy+) zsa|+*0WH-#>vr&b(dtyWT3s??na-&zwpjJS|vCZ>dQk^T=K_N6u6he>JQUTQ6J5pQ2bee!bt_8DdQD<#ZrCm*;d9klp>dLmPyng*w zC9==>+=HGG(zH83>l3k93@B(CT{|_>S)3n~$lk-|Ek0R76a($(#F#ziCT7|$lX9Ud zsbJCuPvJ4@kP7vk$}=YI|EZP_Vy+R8!9Cb)t+B?$b={bjl__}UW#hI)CT|GV;GM?% zj5Qg!tMW=ER}AI#-bY;Ts&ONM_;>EUB>eyDQSw8D?H}Iw-}n8GfWUv{^4C;${}}=^ z|7?+(<9gp$*S=RN`pz2qzXxD6#v=6&p!L`2XOsJOeCSYpf}LupY4_w~yZ`;+4ek~E zk1B>A0k!uPs*>fEi?jd@>R@ey3-HmoxR0&-JMVsee-1xBr|+O&yT4!QiNFsm2x!8J zd8n`*5{-l6IQrU-VqM~`+Nu7kb~O*~YR0{)=B(>6#4y7C7O<%UU^7RtJ9Pl3hx2iy zdhT;~DJyVB>moEe4VOz0P*jCNcREeX(@ZI_u3|c!OF|n*t)h(AT0$GC${6D~ogB^u zR8zd>YoEl~rJ;uxP>hiAvZA&7nX%)?gJoa08<91!}HsEYvcyCEVy;M4sQlyl)EpJHQ&jhXT>#x7Ct&zB{ zq+DoKv28*FYqd(#x>lrEDMewlC&kL`cICFbal74^=fEF-`UB6G7cNg{ytC4E4bTiZ zE8^C;Eek2F#I)j_lR)1{!0D{eI$vHsAzAjq>zk#v1iFf0x2}Bs`YS2la8~2JW||FC zaA>6RBBB?WTvlRS$R+jwN~%LXII!JwqjtrdSShVxTERMp#mIzRMgF|dFlekY#4Yl* zt0C^Rx9)K^pPsngZrpCS2eU;9#-!)x%a<=$Yj=8N?$YR5JFInF&Oh+-{KxJaH3BWr zNCqRu8^8SWnVbu{`~Rer+2YFWw&0vp$E2FrDBaw`C zJaanDI4?jsZUx$g(iNp)nkC_3v>|N?V>I&=`T$p{H8Y=FSNMaRB3pbzo6LXvZ$B~5 z7oqgUMDUsv;QF>vOX2Ay@cbNPknn-?*3PCB#pV2jv!0)S{#p75OGF&Q#MpS4 zuAiPROtbGjW>N|9K5)K>h=|ofiOk91A|m0BVV)h{8*XofxUOtlBW{%~Z)`a-&Axlx zNn%HyRq2(I>nmPevyo(l)&|wt@(}0vHYoy>P zVIy4^igwtd@K`8q&(_g<%$}d0`PV=Fi4Z2CX@7l_q|5otc|PMNPmYOFBG$?^2q9p! z=I8V?U*lI%jZAjCdQ~xo^_`z{x7(E3`pRf{1|uocZ+jJVAj7lsNH|h75**2)|#+U?mld-`==I4zME1% z9?RdB9{B43@Bp!o>#lW}W54&1tGylI5wIPZAxE{x@!mJ0BNXZwp9V{((;%Jc^RBT% zi5#LMMnptR2W`r*8)82Qtic`|cah>QdZv2y?VhNz;;$sH))JubL1U{UCJEegNvxY9 z#!B2W!&tj@-=^Ao+f-LyG=9S9Ai-A}-dx+>Og_*lu=nPuA@pD*qr7c}oS_s&&Y}t_ z0j@{}8*fA!ea{lKJxCMDVD{{s?efgcbcMCv@1d$t#A3|oT0WtOd@r!v|^g2H=wq7QNtVosdIQYF@+P(PC~n_0@Q}dq1Fat97qMqJWl`f% zhynBEa>5u(iLJ}NilU+IZuKJA;5)UFes0Il8tXjXORs0nwO4ClK21F{mT6UlQs&tb zf}&IbBa(c8QjdLdGbL-GR&Is)5RDd}IitlKJjck}Ygg7Z8f(1B`>RG?rK%pR!)uLhplijU z(6y0nE4QlHwv}~TXgT-loeacJmoqO<7ig8`c16{OcUEi!s?Z)qJ+t%HM@F^Xv!dfO zM)%3UI&z7-a+T0UeVCKc_${T)zq`WsuA1|`?S3dUaoFl_t>O39FNV(FKlY>l*Wa@K?+M*}`#}!d zKWuBK{N248E4>Gcd*%A^LN*i?-FhKp1YWdm9)0i2-8ZT3$M8L2k?-}fjSbiC!zLOH zbyrv1H}GyexW9k@_kGn!-n%p4jx3SmsjIT%i2CDUVuX$Z1Wc9@-|dyN5x?ERo5U1S zDIBKQk8=L<_tL4BwWBK4rTLxd0IjzsxE-t=0GrlWZSKI#sGVuDd;aRXH|zso8=q0b zgG~+55zwZA7U@cqA~?x%Rtz~uZr2+rzp^Zmk{i=}CQPnVUSl}%Qps4Q zXXttpWxS6rWGR`J6!XOqPR}gyjpa5}B84)gwSgvTiIa9rL3&+E+$bfJV(ul;N=};9 zD7>RL`}K^iGdL^R;K4`T){SjVY)ir@i+6!w1KtJZ*>gDsYR$cFr1pTpYTIwviZu?c zB+xFsl2A)yT~>bi%V#c^Gw1UxG?_5rynwcK+4%b9D=sKrewex;twrHc%JovJfW>Kc z-C#L#yCzZwf4xy#!+Xc;+Z!>iSO-wJ-L6;*At=<7SS45sS_w5!p6NnL3Y7RExo!$B zfs6o@bzQk_t2{Ca%&t%=LB4UlSEdgFs#NLQX+W!#EC9g=k2PAXB6NXB{KdMjl=W@Txht?iDB@zuGCUV zNujl4I!`oUU0}Upgn8mQJmaScXEmRGcp=PFA5r@Z()yr< z^dCMwO{5Y@c_la}_e|$!4{C=Go@oxmyvlxIfXZL~@+;Td0!{n|-`;M#zTU*nBb>x^ z**Z?AGe2B@K%sU?`$19o{Of0t1h3MQ*hC-S;F$K^0bmsZ#0;;ku zLZ7f!nuERf7;RYBm1SA^`sI~cD^E`stg*eRIUHl|1D_@t5 z+x3k#tu!w(zO5>pGkkh^=K1Nu&wu`z&%b^q=gevHqU^dZsPf?N`$Un3*=4uAZu4ceR+Q7zy0aI@$vE)P_&1?NJjW>Fwg^_kxlJ= zY`YJeFE}sK{@xYoVY3!*EzT67ygP?;8CwcENu~9hRP=v6L+>A2#`yRM)*geaT!lis ztdZL)f?&6KVY1){VDrP@PjRoL%X)<_IvAYG*qj< z`I+zT!x+>5&gGv0*nSIC{WX>hzg40BeZck+nE30z50Cr!5m5W~7}R%uJIed3Z$2P+ zq#dZnJ;%N$?<9%J=vPyqwTPDJ`v?Zyt8O11??(Xcx2chLU?<5vNvO)W_J9l@f0vWP zJx}*7VEgFjaW1~MkG$Leqc2+S^I)w970bqVg+}(?y#5mKIudyzPBlDloprk!q%&4T z%T!m1)LMSG7Sm%`c^v^8_bMBA!1_JFHqM!~&Y&$A(>fJJ@6|J74NW;fQ&c8h7h=xX zHer;dASdV+6YZvP-r56w`kp%hJ18mvMi zLd-Q6p(|D^ls6@`yHpc7#oovVt%<;cG17k}hQXdj5e3QIsJRCWRZ(-1lhzuo6fjba zQMJ;Fc*f*T-;y3N$qHuq5~e7O(oecEDX-73>8K5^P;lodr#@H=mMfV76{>XRC69L`V7^O@`IMobH$wm(d{GuHMj zN$<&PQi`FKM$S?xo6j?0@>0cA5?B{4N@Pll8M0Q9B}tGw1(8Shlfyc>rnMHDH6jD< zEUk%XgGP67E)=Q?*x5)m$*N8P6+maZg!nXDe9)kTf)~?5t`+M8##yG*1+chz#^sE) zV)5Wz6B~h|!~-hI;G~-tVVdd8JO{3?6K}6>_qPhu#5~V?6*I^^$CQFz+dC5IXs8PyN3M@a#qotzePZK9R#%iJPs!W(14NaIFE@;pN>lDw^OevXl z?LArmO;oU!Wn)=W_w>@8`YFC?HEU`vc&E`yeC+06 z2~MLa&=Mg?|6NX*rYfawtP$3Dk!oM1l5%3*be~vcJS(N5l|0*{ zfqG0vBOx*9EXK&BC=}t?`v-jwLZpW+Z%tSgNtALWSd!jlT0=EWu8CNL0z94M8lFxQ z%5-h^QejM-G?X>y*1>%jHrgw9O+nSPqJ)WorWGwl>$M3BKuf=JtB_+QuBp@5i}Vnn z_m{d?X!`~5X|IfI5dT zu1$O>SE7KnMd;_=G`y*JD@jJ7}4k<|4=4 zy~9v@+sIv1&ojb z5~c}ng|Dv_%+m>HJ>fL-(lqOqxZSpX1B%~D=PuH6A+18eEX|N((VXauV*Xum}}SJ5HyGvcBCS@?g?6OMyZW0R{rwK=N_naz)?Nt*>O5OGtVLo9@j`d zb=g&IG1_AsIIA!gp?vB9$>Df|45}1#O>%*g23^q#CS!RDo-jMS*KAQ#l}(n%yWprrwL=9a?uK(oRj(N)xxlx(X{3@^wi~zg#u``YmokQy8Zm8zX%exJ(?qFa72&)^7pdwrEq!=t zjimKPO@$C_uO3ZQRoT)86(;NPAuyc+QD=F99 zOXvqNo-Y8#Vkg7NOV!o+nUoZEKI2Nom*~Vc%V;tdh;`!4vK6tdYOkU*Lb1FN1`F6drUT<GKE+sYPU7O6mIFtdGh@D$0w=W{M#?wt_j)()l#bToyH_R zUZoktoITJ}8sxG`&r~i#BMb(AGWgkujYutMS1}r#1LGCdc12H9FgkNSJ80*fo)V)X zl|pG7>$>r}+*r5B6ap64$Ev(fl(C3?N4{om>s2PZCi#_;p_ocBLgQ!^QYxev#WcLz zrwkMA)`psD?7_yE2rDse-TzII3&fP!l6Xv_q|eh>0c_XhE5>M^US^yROn#C|_p(7s zkP9XEo&aO0PLf|*OGZ)|Nh}28QOZartW%n0QuKfrGw0luDN|xwa#xt`0A4kgw>REC z|N1b|55rViL)8P7rnaL&7d@8>YJ@-%+&3k&wbE4p=AeQfUs|F1#C!yH&T71tSJVPT zN99!WywYqOC>bpB3oV4YNlTRqoNd=7^O<0C0?AR6j2d6(BY8!S`yaFl6-3 zl(`?tz0A2Q(jAb&BP~Tzq7AV9f8g0?Nrp?OLY9satBq1yXdgGN5J;&owl28dgcxiZc~rfzXJ_a@1X4!*e2(>G{|UbgVLX;aa)Yu zHNC&awUsr>ebNqO?|#3(QwMELbs#ogci*!6`%QB9`%7AsQf#CsF={FIakP(`Jf7($ zNpTKfgkcVSc*aI`@twuf*#BC`z8w@GyLaPg19+&g4LgD+3C{chNE_;qt+l)8UN2>i zeU)N@LL2t#nbX3c*#TSs_Zz^b@9L2Bs+!TGrKnfY_VXh5j?&!EO+PP!Wg1p1Clx3y zR5NRh&|PwtQ?B~}r$pGm2QfaTm-<>a_>EPv>%~IN8wv@^yqlovF0#<>W8589?lRXo zWt!F$Q)xzM5v^4kNhVZPF-CgT;ud!SlX;rZimsR^w8+}-enh28uftHaX$}fE zE?MY%S%7HLh7=>)7I*J7=MAmS7^exwgI1JQu~`gOop<=j6THP5p<|s+GpI(+j#@LV zbz6cQcW!XWjTFIX$5ag2Drlm-Q)@$8-DSEPjf_$aA1qb1E(ssIfQzQpilJgnlU|RU z(XDVkov0_!*5S;AvkK=x4Fhs*DbAppB_~nV8=g=!dDayO{Va%jp!b@ZHnyD5R`|7{ zdviG}#=_2Of)^!B=S&ZPKxG;HhsvCFA_O7VL=(x>EC#mLI7;phWohJ8h%vDaX>#4O z5#7jI8R=a@$&IhAmVT!m6x7~>dAgkN!HF4iQ+q~4H6^^}QfNvPJ)IN3EjM|5aO7@j zpsiGveXtm7v995~Mb%EZbcSFjtZ7WMN2$iLY^W&5tdy31Gvm<4?Go0tiCu!ynh-qJ zo-j6GQe!#?YKxpMf%7F$iVUDJO21p9(t1y$?mczdXy#Mk`Q^eqpO~g;AGA;vZJHzm zjOFF!!ufLHFMs(;&ao>TX_}Jfq_*xQs1SN+FgS0RPvXzGrEQmX4^!x`sRKbr+%|5@ zg2@(>4bvRBJfDPyT^pq)-mXz7$ElFgO39C6I9iFPoT%F>TrkvD*>a@T)D&m(bHCbsb>XuX3tN1>6E|;@Z zN;};<_6e2RsHqaSNVVbA(oJttA5tVQ}ELzvKLauW5*R-|uYU01PvSQ2TI z$+y*p)sUi$N#8_D@=zTBTf3KCTD!+G{W_0+5c!Bk4CV!JDHOW(ieMXfPwoBLBa14% z3^K8Mqwq#iJ7C)bqcI=0!*1TAuRZ*ceR-@9d>s7$=hjocUHcKZjUVOr+!{;HxGfR3 zMA$5|w}ds~mKEcqs*lkffAkbVLMFluWh#vx#5k&0~%mG>N!TbYe{TQ&_S9}*;e^`3-f3O&SJj*@PF9-WAQ2af> zrl0^bLCn7Q1%B|Ihp!$F=6-G8-+%weGSU%`|GgU)KByORki9>i=-fimn6v!B&295Wwj5sVQz7L=kW&gQ79Kz^ZYlxMFRMQlt8FB|~>+aCA%-E6w;=SS`DmpWb@FjY;>q82Y6yBy{v*nyflz|$^_ zweQsa+#afG>To^YCo1~jSoeKxlmXW2U1%g9de=&yLrTX2sb*5mJ-(3SYVBUA_r5)` z*%~KUD~X$om1MBBYVS{T{dM)@WKTh z!WWH1Yo#08IdpeH+Ln#mZK34~73rPpA{(_if+NdKoeXsN#2C&xTLTfrO9%`hhO zm@0AEcr$OHI~Bp`-c#r9jjKi+=ffmwnlVYQBU(U=^>SUDb6u9UfbKHyM(BFWwg8RG z%SAH%U7lZQg)WJv!%ic#)^zSM_+Uj4heAaWrily71hqf|pK3T+gAa{Ty*7ykIuAIUlK`O9AjljZ68gtMAbBDshmb}6Y3#Ff@E z)_I%@l($G;H;jez(=6gFv*moAxm=!jdwZj_OsR=nHDR`#E)%U))@9{-yYlw>22EkL z6F)OurJpm50AIYXv}sh8sVKI*@%r|aEp3#R@pj_!bi#Tk#`lxiueWs;8wwf=%~7ky zrbc%3>||!yZp3^OQ+HL-4$>BhDNzBZrGi*7G67)wy=b^R&$vnP_3Kw!YuF(7PerO^ zlbb}=-Y9IVSXFT~p|Aqlv;ef!so4qv4Gz0!bLl<1rB$Z$#A!b5!No1zs7b~%gTZ2P z%28A0c3a6ss2{;gby&=|*{PH=b~@(y!hCv0sn6V&O{(EmdJfO0nbs<$Btn?ET%M(h ziqI87sEe&Dc;!@RP2pUlR>Xj<6W*<}=-{RLdAsh5M_)QDM;L?lH>#Z#%>ihrr-54DCU)8g?EMM3uW9)4q;7hVI$Wd)iy*&Kg_?Yr$x8 z)oiLh0JM*G^?UC>?Dj_#qIcA=Z$tn8tmWMndQyMOg=}-14nOxDtZn!-_We45twDP{Dn6D@ z-K?#WYb7_)7svy!^~q@$bQupyXAo(ncgnjl64T!Sn~08>4%&2Y36km<-Ky+e74hM4 z-#=4Qbda|mpR;;M;nBF56Z(J&<9wf_ls7W05yzM32GBGYy|T5vZCvNsH<@W*TqMo&~>_e=Dh@( zQM#Z_rBsEY(3Fs!nvw^zYPsoKzxj=|%;ytTK`IGtG(H4e5Xx5U3OT6=Wl47*y2c$u zgbsK+1Fq4DpdIMy$E;bowNQg)ySB=%#78Ne>+|Pdei` z15mR8i(C`D6RA{EDcp13@pQA%;U6-vv*+=O%N zG+tQ>9VTjK>;4C#?5Olfn2(QweR02;zJ?;e#jT8!^7&yk?p&oX%pt?wpmXQCEpw zv%zojtW5K~)5o-Jpfkq9bheach*{B8BIX;CV@;&8a9h9Pofj&nKjVz&?duzV`S~vx zZ8)C-)<`8p+lKXuSSzJQN=+yOesVm$TnHhMYQa0jG&^!B7^izcC_#YuN{ToJG@8o2 zvI5G8RY)yL6k5q(Kv_don$k2)_v&aXG_A4T;R52pRSOs}UMj9OSmw*b>2#7Lk5O#t zMvN<;o@Y{)WW}}>&LObQnYY)4>vf|Qg{ivp`A2TISJ;fb_aLN7j-n3fjmJArZ~^1M zday;4jUj}IX$m_{VM4NGY8< zD3!E9y%|w_E%yLfcN-XC5Xd~?yzPebBIvWMH)^d|t4UcztYQ=atdx5)t~Tl2E7HSx zTy(EikI+v&geiwPa_rw8(1}Tj_+0k!tYoPI?!6Q}pxEgvst3`X{?b_>-Z@gOq}GV7 zLaq;i(_n)ggC_QUK1!l|gUKG3gQ&#&IO&mQ`8O_oWq(DhketK5rILk`yWSSA8YT+1 zCb?^s?md^IAJ|EfHal`MSl2XE9vF#3sItZ$5w=~%er|bQ~s>A&^_Gwht2Ee`3$oW5Y`XoB@ndp6?XMil{#A%Tf$(tm*nWtd)lXdSTCTF5OiPcu*FXQ86` zuxFK>bIkM1poFz{ZzL=wV;o=_H6>C_eX@{j{pIoP5hFwb0`9NJo9-U#!| z^UE{F8B!4g+qdhL+ifG}N^n7_LRGSOLdlx3#_T;II}Nf9@3#$OJf|rTg7g)|O;qug zW$DI*fq8b!v*Y}9!C2U0BxMnC(K=&v#Tu|$;hkj;p7Uwq>1pOPdD2$+`s*9By%5Yq ztp;B-&WTUb+uO?L&sTD)I2W+S3n(@foX{hwg}5zji)RY|!cTwv5vySizVBx}C@sq5 zmQrL{7K}3}CaKPyPE7Mem?!@2fBYN&s_`m-*++=yZeLC-3H zW#M|glFGu@w-v25r?Vp$!)>i>>B=vk#XHbhLsc79Z-jZ`hd-YA!;gRD$4`IYzyF{A zonL8^I5jiX_Sc@?1|)u_4=izHqO3FRQ192a%s z(+@9v`r#9o^Ao{aK7aWSZr86&^9gGlzy9*d*Dp5|o)jDZumAV|$uEEYjA&C@=o8oI zm(plzt~;2$&v zO$dRPmlyu@r++1-jn~&#F_m_%tD#DwNq0$OnS=z)iz0066Fq&d8Ny5z<1`mD15jHg zZX3&TBgWXPdD359vY1f|fXaIyTuSBows2fjE8TA8m{A{jdl;F0#T}^KU!~g{BixTlW$j|YHs55nI^HGH$E!+$?o{=RVg zzPy)JIPSv3evaU?iudVyTezvlq#C|ev9>X;&of4{^tFnOMyZr6>=dylk))w^l4$Lv zqPtj0PxvZ&Zg{UYJenO#B3+##~uC6!}$2S2QYTOEC>4Hd%!j# ziFQad{0-Y3m6);N+N=G0GN#tOsLge2zJ4AKm-&89|Hju~yrn&+F0xO3y@NBS#_#=? zdmc;k2yXRphYr`RKZA$;9COBQ;C%pOt-qJccK}G3amY@oHLYJPPs3S(dF=M(*v3 ztu--C&Q;8D*R2D!dT+Swqu*(ou-33{utqK70NsD47V+3p56Ja?z(xzjvgtvRk=`5C z8})`?!Ck^sCIj&d5;2ODQt!#>*}d+|_8?ulAA0MO(~023IJxx!uu@rL#F!=-+ngv( z6ff5pF*^mSVVp&oM2VSP3#pXuqF#3DPD-k0hQ-8oUDxi9G|u(i8!kohvJ&IIAqXG_ zxZ4&uHIK6*6yv>R@>#?@3Zz(gIzRJ#dE)8m#OV~Im(7UraqxlGgqo_2lv86A6~(wo z#nc*0@PQB}f}d!06IpICl#;ATtJIunrSNnshN~FYMpxq zR9=lyjjZx}6BQ?|49gqmjPA=d_P&Hlf#FAwU)QHHrU?Xy&) zy%U*qXF+F5o4H&jF3*AUlVd(xP8Y}J*<-Zj>C=SPiWtFq%Y1fV1LrL;RY#a7KK<~_ zbe8HiS%N+Bg4CR!PGSXNJ+&!PlmtxNL>}J`AFavm_6!wpv&Cic=Buhu$Yg{LUP_be zKqIvXwNh2>)i{Oqn)CAsfAX9!C!sMuO-z#q{lpX`P^hKhtRi?VNfWD?yv3P8InRB5 zYd9;4oFVk{r<`PAH8fSbw7f7MN=;Zl^Yk=htcV0j6exa&DHWy|i6P>>n4Y)R1Tduy z@dLEXr)l>eEJeoYQWCeD2&8OVWLqLJZ72ov91vf(#OM_$B@v_Qv}m^n(t8-vde2%F z+PHXrmOiG}-hUuLg0*(1nAG0a@UV2dkjFS_0Jc6O^tqw7(f@q+Y%HBEkaF6CmEEi7 zF!|pT^@qUaxV_d*&U+?>Iv`|Bxi~GxT<*Q1sD0G2?QlQqZs%w$TLX+NEt<`QqYkCjd`=I_F z_Z;?eZ&v&k?KX~p?Op|XSlK}k;co?O5_Es~r-yAlP^gZS&fcR0qYp-P%2~hrkJYD9 z5_&kko)0*jpW`Xo1M9VX5*Z^tw#FYBx_rGU3R(=OiDZ`Jc)lQlO)355dZdx_*16Dnr zemF0`wViJ(kB^k$M{{XO&}Vj`n7wM$WAt%F_T<91&&$Jp+%M08;c(m^d4G)0<8@D( zef#tAcTo(Nxat9@js1iUw4`|Ch7opWeu!`gcfYj5OKBm^?tfDsRM_4Dw!h#YmBh!J>7m1|p|t(}_MdLShiD(B3y zEL^XSX*PuL#LLSw-Z^q^+-@u9@Rbw`pPoPQ>E(qVUS9A{^ZCoqp zVns@YWqBp%#5{?r<2)zkdF6CEaXQaphP+9}-8jn>0^T{6>y^L!`Op0Er$6xHk3UgM zVY%Lf9$KV%Q?5ak0J9G&IVYCo%G>RY+FJKsGHlz%FTegGH@G$Z)m`GPq2xqL8`?c_ zehQp^nD~SKku@&dmZeK+yL%N^SKgL4ZrhbqBj}2Cmec8i^Pl88m#tS@=%OL=z}1#% z2+dYmxNcWsiZs)3vm;DH+(AJPE}heyPC#JX%O z>#xM^mCI%3a+#UJg!PW53so1+&nKRrpSWGG)TLWFIH4cTQ{ee!=K1B!k3YWf)4%)? z?*raRb+xsMY9iksTP4*Zl;NB?yTIw3- z(b{x_Z?TO?DRH~4#F%NNiMWP0)S9{7-bigDoE=R~eEobSrH!H!nT;(bO6p+L8n(QU zQThWlf zN8Z1u_V*_Ahsl2gDTx>}Tg+@Ji)nYarZ{^3jCpLAZdPi4S*@{h1E8t|H&RS!Lgk|? zQ}$w88vuekUGg0qeVo=?dx+DIKS9)hFsxA&j_t@ruP`yTD=1C zSYhiw?@D?1O#b~idjfkmD82`y<0$V{jPC=s@|}w}5-|IT?3J$J!8Cp!>mPt^4;p!w zv9D^c8jNWEP_%kDrsLZKtnSr4#ojaZ&~x;6BDWn_9xls%k1BX5Ex%i&20uzSAFR9Y zvj8svH+z3oV+SHaX)ZhXI96o#ZS4W~@M#6B6xKWfveq8u{Eyc_Yke;ka0KP=0Hqp# z@B7#!K9liB?#WUcc~lFV&>}UhD=IdOlIm$yQe~^Ek0Y8xh3y@HKY+8}HqRcq6kW={ zd!p`uO(`^;0xwsf=L=d-D71bnJz8qi!?-&@8e@NsKye4I?ECTFL+#$Pb~nu4DUxj@ zi%U=b-G_rapwfF0$?DOgcK7HNHjdia67NCVE;yp@>l;&RoKS0`RHD;xg=C8 z1SStp8JN-0wBx6-QO?8q*NN)D~ccPuyy&S^?Dxa_17qz$R}q#0wo#I8nXl-CN*x?)#{yH58>u zL#gg(wJEuAV$R){OF&nymB}c=JfXCvR7kb4#MCq6LJiG16BUf!3uDb*MpjBO&l56H z-DS?>mPMGQfwQ3lo_h&6cQ7Q`<+i6^byqI4S`-B@=Mz8t@XX{bu#%GDhfhzO&u3C> zy~@E}1(OP&cxG+e!nQ3a)d<0}c}I#C5QFF79h3La8ZoZWD&85K6{Vco^DDZWqOMzD zjgpNY*SI3orj#?SN^&5#%ynC^Mx%|P>WZ0cH!9SqVo@IKq|pIPumtb1Q6_P%l*q^< zK@M6JG|`RoWu`T$4oo31&w-q~u#N?rr+pxwmpC`Pxl69+c zEQ3RCtm5=E(JZ`PbH7g;s%lEVS#zsY1>Q@4o3@Rn3%W@b$5f$(+?;k zeWodA`CNh0gtj}XM7~p61uRt7HL-1xxQddZ^_G-3Qd`Mb{1gbYD8$y(czT-gHsFFL zcfUgG6mC|SpgC#jQ`25kR6#olv|4MFR#?(PZi#b{>UF9`lqjoAd#z?_Q~1epc{!6? zWy>qtSW#9z8T`rOCWD&{;o_K26PXiLcV*n1cH{9d8>U$(spr!~>c-ePE3~e7uTcbs z|6wW-vsMu}GM3BJ#HSxF{r;B#)LJ3tC~ZjUuGFPW!P-U$np!RAizjX}aSxhGu8J*b z(9#Dgz-9Cqm3{n!hI5VvY+LH|8t~3@zFeR-UcY`Nb*0pYz$8EDv-JQ;eHXB`;ZS=B zR!V102uREQzN*sGQSKSt*0bPhfHfmj8fOi`S*k{oD@wBarOB+P%P?tGdsS^$%kGG6 z%#g=mcR#KX=l%wo8^Q6NKl8z7e&_x7VYGVpi#Y_J<2}{Sv5dKiMH#HwFj|r&cfgiO zv5=-hN`>e>-k064&3c2Ittb*(gL4g6$H8}V+1f#yR%q4kdCx%=Q-_{4z6EUWDOh)f z{rmTKz;*y>j4D_E`J*M5uJ-rA*}YSr#!2lxe)?{jdpFUQ_(U7Mqwn_=E3Nd%XOCv0 z4=%2H`1wfJJOcf{s;v80EXT^>!yPql!Sk;H&ev|bq>0PQ2+xB=!KgiZMNxp`PV{A25L|6TN>R(9}N8@uP4 zFlGDaTGuVp@B3B1z5ag_9kR7|V5xhR^(@j5*N{7{CrkRXG77(sp!M;vk05dHOFMu` z-T}7UuUQ#@yWZvekDu9l*z!THA3#Y}Y%u(^7Lhu;D?bVqQg_V^rMpmG2W&f#d#I#6 z0yh0SfNk6_?|*(z<36TV?AO=NK*kvGK|F&RB2x`McIIJ*itgynj??X__f7&lue}%?|a4XKJ0eoKFPrNgk2N zCj#OvSBqm=5?{Z3<>#OO%+Ejn!WJvmY34aVl}ZmvvYw|oFa_y1Dmk%Suhf!zWmLT8 z!YSar@9<2jTeW7Kwn8Oz249_+-co70k#%Ovg|Zd20e7+@f}Ko)P@(wkXn_1NoY?>IjSmP!FofO zJ=5f|M$>8`$4E|5fUePmd7@dxHLZ{ny4mhGG^FDUx>dB(U?G#xxuJ^^Kf)ZzCHL&G zk_u&(s%33b`B5mgBu&7z33YdglJ!!?Qk25Rh*q9;$;4RjR&$=toSvk5>b;k~qXxz~ zPM0VAG=bLSQgGJcoo7A=o}MO@`iYm9lRPt80TQfgT?v!j8@k8f?5e_7-A#o3eh<4> zg)&)u`+~s-jSnKEL2jI%9H;XOX^U)Y!YT;XVa*96`r4FIcL9us$o9u%MQFu&PL~s< zDcZVHH@OG3)wm$nO)64OL=Ef^Ffg1h6Deh`uM4>}d~n374wkg+w2MLKiZOEADk)m5f~Gao<;=DfQY?E}BwRdC zoY>0BlI5IQ@31F>o&jH}wvcrqvY{u%tY^YLiAmDx<;R&Y!+g@5&W3fZT_H75+lJPf z5VTMxjYXR?ZZhPQ$R+W|pI-Rsrx&rVpmDt!tSxAB!h6TMEPVa?mG!o=tr6#-vSEGW zhaWF87N0r#i2%t) z5~hrC7`-6_yu=haW$8`Km69vbSG<)9n^4&eQ}fc(=4_V~?@FUeXuwJ-(FAEcG~5XY zt~&tU`(#@C2Dg6**jnoLGXNpNfOvS0yd*H&UU)n0A$CL zuMX=yHXA;muj3ELFFfA%$5oF#Q~VR|ovws;hims_3CCdem_!-(((mlSv6rkDe)hdr zik)pRUIVb*tLKp;#c|A6)=JV{HG@(2HjP^AzP)2V+k3F~_b+Wf`E5_$$nX2*-p7c3 z%8n=ZAKm(X46<^0Rvs&IJyrKRYf|HA9`3Q@`8m=cKN3S}9jpxs>wA;y`VO$Y7ab9B zEf4bmmV0HagEqUrI*9AwOTcFrVT5mi+78Zo-`WRfTGbVgv=Lwyf){gC8o5Li zmEaB2WRurv>3L>ot$JVs&SI~BTsosTq z?$gicPn3tUBV{F7sGOSw;L7%%i1zNGx!(Y(WGQoZ%8xTn{B*jyP56Ieb&0m zdEZO$B5E;ExatvzrWWbJQ6S1Ut@geRp&Nn1*b2G_kE%h-pbE|^nl)^j_*dn!k;{fQ zmJkeiGh}P2RrSiB(8#=(-X7_H%xIj*K5!D0o=)@b-&Jan{8y_&6LSG&-YBhL zgFy!)m%KDtzjwWy-mq5nJ~fSUT}iZwFPxtoB`adew9?5^Jqa+XH>HaONRTgC+S)oL zq7+Q$dkhN7E)(03L;{H4hPPFSvsxMz zWyR>ZDd~rl{}&obQpJc$VM>LT8>6#WX$go*DLaj@wZ@hTDMhqhCE1}9G)sz&n!&k% z^8x2P)_II|a-F9cr46UknGgbDn(8GFEay=h9x%uf@>TLCED&u@u0v@&-oV6D5^d!bc_(}t=I zcACjV3ZlNMFle99-Vp0XHKnW7dWrH z9|7P{QEsi5SC9%@l?g}$R7y8+mvK}QD3FU#<@cVpL$GkKvZ=ko=8^p^Nqm(QhSL2> zYlEyxPk!hfu$9&hij-AoPJr3toDoRfD?r}>f#c7OPOBP|Dn0RjuX*&@@|)=Dd!gs? z{Xqd0ij)A+VSg~}ylR#6wyYxVHD-7b;d0`=n8n-GyC^EqRu~XI8&b{qAotWb08!^2 zev?Ctq#i0x2a4C;BiMQ_WCZvlX*U3R+m*1Tr&5l#jh?ZdG#ix5#;5|^rRn!ev>&6; zBKK?cuG(G zy0&9)4z%um_PnyX&Xvnda+IDe}+MmliJ-r;j+MN=4q_+-mN2_~MK=-lE==&UO z_0Z9f-ZgVD!oE`<71~N6N5i)jws8)07d{$QHZ^F?cZ&A=3fuAi8Q0>WGTX*kle^!( zyqr<0;hf=gn(lLjEm$T4^)+hoL-UYO_Ou@3OE7#W>udi>=KpTS%Guk?0 zzqsqVu`U}WR!VLd)ji+5?vlQ8;H8P;SItPhx2Lx%S^!_K!qqGT_29q{< zk6L9C^xjidCdRm{S~~BUd=TmQTu@5CVt+V-k%aUohMS%7}eNrvd?`UmP|x9 z@^-eX==9&ccj&6g9SFseq&j<^dAlv#mKzO-G4k|u;fEi80IkS5F`Xu+r)jT>$^@lQ zMs?~{qSh=yv)9zBP#LsU0&eoFd@wxSdoX5QYenDBl!giOtwuAAal1~k)Ao}iB4I1 zhSxQ*#X@a`X*%(AIisEpamy^rCjN0b@BIc;@oc)};61 z+zoLDU~6yyTw>f_$+=NRHAflH1qt2MAtO9Mz&*6wX^~o}z13)3HDn{>sp&MPQoFy? zo-OZ+bFHEFs*vi%zq{P?==m7ngZ{bi29AeuW3O7MZ}Y)z{AUju4!}&ktG*nA{GL-9 zl+L}taaeO}jg$*oM_ASVe3n{>$&rin1_m!y2;Mt_bGT$kRm7D<`A;lsT2qottkTOa zfUO5vy}Z}jK~&-Z*v0|1&QK_ORqb9;-D#5J5VRyyC7~fAQsX2Ek zeTn<~I>&cET)tJOJpS#Wigtfj&QE8#jP)Pz*H|-r$6DZ#MmFNV@oIZzit(Jbc9;Xd zRUsUU*pAfwv!w{#_6T;~(;z?UMS6s2A1z}Hx$oco=X({c^ygo-aW?w+puV3}d4HbX zSO4Avg!lby_kOXv3h_AhBNgyHV3R#6dtPFUj13OQH}>JaAEmTTaXctGw%&I*ELM7p z(C9ZVMSA9Cp9^>KDcL|r8ECEg9NtwR58%w`yXc5L%+X3KiB)!R_K~Q_=q3FaupLz* zzjs|ex*mH{uK#8)=Mx|k{^cx`lu`>ZN@k(fLX3slHr8#W)`nI>X&WU{k#4_9f0ouv zt>VH&jET4jXxp|(j*Xf`+0Gi(rRb#^r<eT;4uPUP_)vZ$bK_;vpofNF{1tim~sGKHp6r`#pBw6Ud?ltrLIGKBZ>R%<2wfXY%L z#I2A+#aanYtJ37ANJS_$xmK!@@ObNeV%96rmQ*Sg#pD80xc4Der|~YMyNRi_9=yib zj5Zs_im|lu9^*XLdtC5nXC*i`fKfQ_v07B;a?6}fXXeu^0JcPO6F)cYgyP~Ssjkc? z%hQwFQ?fp2Q4H+YFPBV8qLe5%wCS(f{j-D;L#_huilMfQ>H%0O0+MPQq9Ow7RG;J} z@RA3;mI9r^Dp~7;5|pasn%Gi-CQ6wxZ*vf`)XD37>p4w#gr;0W=S@T-VVShEd$$7x674Q6EzpC zld5TOnqc8_^0ZGE&Zn7qo|(K8wLvTL?usgAictzw zp*2aw7^_fC?su(a5-FwiiBc+{-Uo6nopPn|!R)<)CP{D|h6H`j!di20wr;gzoK$z* zamQx=;36L02yI7tiTDgKwA_<|oH@;Ji38Ov6SekLT)0rH_`z)u7iUk`yb_%G)Qf{Cp2d-yL zk-lJOHPX79nP$U}`ib=%Sl1-9Kx=mZDOuahvaY;cJ?pZvZIRpCLRAZ@X{KrBa=GyG z=@ZsiV$8g~UO~&aX}!#2-uj*$Z5Z7+Kh1cj3H}kVy}iYL8kEf3J;AXDqI-o+!ifRk z1h9$t%h1JAMtV-QEjq86!U8go~V)CWd$BIvDhnby*I2qzTjIR*J_oyt}lOW|JPr4?7z221x_G{BzFouA;hS` z{Nu|v`@i4AZD$|cDcLfo?t7?yo3z@F0Gh)%(H_-02bFPv#KBtF0bAFC*a2H>JCJ)2 zOgWqp)8n@tjJ^B$_)NX>GO&3sl*dut%(0S|LhUMZB3M#UDx(ljve(yF6c+DK80}G5j50WFv3?@Vkr*4P ztOCNk#rO<%rBcaiBi4;IZerZrsgGJCN$d7P6Wa}J#7>pV z1^)0!lr^u{D>giFnJ!YPixEY^Xz3@6TcNfSHIw5?Qmt2ggtA$BZ%E9Q zb{hjj1|>$!c)p1Nj=l4r(P z#mQEj7r_e=4w_lx%G=v#8j7dqPe7s82voecv{uM@m1=sqPvF*ga?)g@i7}CL#ahMX zY2ti7Q%dD8fBA(iCQj3YF;>(LYr|SE=MtH8Vp^!R;AvRha7IzAMFm5VTnMdIQeMbu zrKuuG7L`E>6;K-kwyTf%ikd1X@0nfsMK))I6&12UU?H$?#oC!R?Jn?k7aCy3*6s+rt zpBvgIrYpp_;jH1)^ApZ$V%$(5bYAcA-GqKDzy2y?uTaGr%8p{en1H2{HBQ?2c{JEd zfa*qa_o2$gB1-MN{>? zx8qT>;@b+CHRhX&+5OW(i8?~Mz3;UD{TTH~ zwn2r|8m;S|Ss#Z!GW~nCUWHZhl*k7PWdGZEf5+NKO5{iPn0j2#hadQ@MSbTJ-vG>S zKc((jj)(reqf(=sQ%Ts>s(*7|_sZ6x>MGUi_Z5))=YMl)hja7z&z_)BT|DkiRlU>b zXx$9HBJ3g*irT4??Dywb;V_X`jK+#bV0AynQEmKIDe`@lZLhBN`&Mg>YKQ9Ds3wi{ z(V;Rls)Vf`d(`d%BS#bLZvor*JwE`p_r}?y1?z!Y+wWg9`qH``$lXqC&?3isqo2(@ zRM?cT?!T$9?LR*pzuL$2e(8H*;kR-7`zqUh;~cVIme!bjz!=Gpx6;tc5M1bVr%bLA z@Yd2$x?)Wx7g(2#b=yc${MJgZ0Mwd0@AloG)%pP0AG(KoTq~UQIIB=z28KqG3Rf>h z4@!%o?%CR0i_jzx1-R738ngn{q{nL9&_)|3Bj&CpW>LS?8Es6L`nQChvZ$(&YG#d* zR*NXoY4(6wD-A7?;(|gd03u#sBw3267CP_Iw&9z`TJS;PfJwfjC>U@ylqqlDw&L06s2mGHM4GM5A;Q1A=8w{I7`lox3`Vk4U}n2lcn^BKW>@0 zY~<9s_e~?`hH-tcQwFTVC<%^jm@wX>y+=7qDw!=uVo6lhP)1|CMYSdd#$N0XTyV_i zS%N%Oalul_*q}KvGtCz76w!h;6{8A@idGe)K^0_z?;dcqQ~ZjNb5r+Bt(bf#9oaSk zT9qyhixRJ`oF5*H*2H5k=Clt6<6*be2zOZ@2E4>RNF0-|LZ=jJ;uI85mtIEK68w#R zN~MNxO6&J_g{t-eyOvICQU+}rrHZId?ZO164e6>DJ`?D3TGP>ODj^b@K#|}#UR%~wI&?+ou(k3gv++EwMHt1>$>r}Y;4QI zvRsAER05-KVcRy=Wf9Q`FYCxT&)9T~W&36WCpmN`yrW#>r%@n|SuACflUQ z7L2BsI>Z-kJjcR@P`fd4tpeh;HB{}$P4Dx8H3kzrZVrSr!KNT0eWlKzg2POKW;L-E z3XsAww4(dRO%7EX5ebr&mg+90qB@9g7G_mYPGcvFbAezA&Ul`lhsDSQs_qpn z7ZlIiL`)mOTmJCr32QXVas?Vwmu26QHal-;|MSs(OH-$E(C})ZNyrsb}F@vX&XgPPNFCja)Y93@8^&UFfP53VT3w@H59tf zqoNvjIIxdmW~Cp-s^c>7(s32ivoprRUQz0w{;0R;BW1jA_JQ53fMZ_zUI|ovY%)8Q z*IFauBKn@y9x7|2TGXl%;A|=;RkA4uN?U(Me+#gUUZ8rXBi0_23t%fdNZSG14!&eR z)FD`VpIsk-t+snrueCc+9Ezaj5MYj=_93CsDZkb>VdM--l~JfFlI|i62c-vz#tcd| zy??o@8fxXw&MIT&y^}WCSe*H&bzKiM9_;34u4QJeQiXEeN zrhz>0<5jA!lMuQ^tD*zJeyAD`>v>qDvh_ph$1*;*Ia(|V_8K3%ENG1W zvm;>q{(fXiNe`6F<98nDwEbM(RT>f1N2NMj?{0d%QzDJ1L>?6*2Y6FjN#pPbfNiHl zcGb!6-UW}C`P)Cg18WZnfOh|?UDuVLe)pcXv2d0uC7eBGV_r22`tkpEHh^FjR5k|SO52&NhCj`TEnelUA$s0>rrC$gcT;nE9 z%B}O(TT_(I@0MPmh!y`x2wcC??EYQt1NFD z%j=4FmeV|;wH&i^lC^f$m=Nx*2mMOz7R zuD3UC%Z*(Crb=V#C`cCyri!Z9r%#^*)LIytTc?xbbh+T2l?tN`oGwQCf7XmP8tZ4` z7Rh;|Vo^p3xTu|K7am<_pWEIyNVnlHGB+|a?Ui>#K4`dpjxYl+<4FH z>)Sp!f!c$dc<9}1Lp-SWs3|2hxM`Yp1NO8gD2>zU^e~QmeSPEY?F;AA#QEg$-VmHr z5xgllCj(eqBdHW(E_mUnM#=MmnBX4hS*v%5-N^K(6Qx&|uz3mOoAfIiuN#&~F4=Ic4;kHTdU8#wt zMVO~n0gl>wv~m*sXAv&ka_!uBNsxIr^}s^myz3Sk0cR}hdSlyG@to8OrA)6}biKo# z!PBZgn@z?a)s0_k$>fo&Q*gT$wr%MR)RuL*p}u}WE5$rb&>AIYN>0Sv8?9u5HyG6@ zSrlf6rN_xTPLpR2Qr)uFu&v#btx9rYG_VVpX?=dMoK8xviLWFlA_~r1w1!$UgED$P zpLl-0^mS#NGhEISM!~kNK*PDfG|yblPY;vffBg9?&RIuy;Gtj&~w({ttiNPFRH`$ zzGy3nRILEEKuN#%r0;u*TFzadtc#A6UNsePe%S7yL`rLI?~Unztqy^yJ7B9-#Jl#4 zy`0(K2W*E*!GlbBw_?eCoE)I>crM3x0a4O*74M-<_HOmkZSO(LQEBp9CBSb@lmD96{ovjqHSWJE=oF!zxE*887!ZzeY7^kTe|ub(k>F8u z5YfZh1L$l@?f2QkwfVg&Te%B;h@aWLe~qR^bnTuV*;`Q>{re4a;Q-j~;vnxUeMixd zqo9a@we%?8-=Cqz<9Ilz_@k=klono|?(gql&F(#H`{&j8`2g5-qaLd2zX#Zkmw3=h zfAax2{P{2iF@nnRs~t_;KsS2Myu7>+rqF$Fq+z|bifW2=T~SSmDpt=%siqzp?Z)m} zE2?AG77@58?9IVus5vRgj2R79oS`*JVGqTRQSI`>Vx%e{prj#j45*u0x&==Wr)j_EQB3n$9m|3?? zD#s;JYa*wOR-)KfqzNBHxM2!`5}?$CvzB$+SYnibvsSLR8(-hv`tOaH6EPPt>0Y8# zv5MYRC56ra+a?}(V}i9V&mb_ah1DV zeaT4-)6-xQ4E0xo(ne;`YG_J}?LgDLx2_A?GyyoyT7vU9YlSLT8zuFg9j$ubmXR%J zO{u*%v{&cE_!*QEA)CE=Uu1X|Wm!Z<-#WP`8%(n(K9+2VMucTz+JtpsHPlQi0;H6Z zd(=Atmm!FCgQ#Bij*C`AXkk$Ax)ShEP&C?NO~WZgK*4T$JgU)RY9G8~KFzq^J8i8Z zbT7D+A_{QM6Q-Hdbbgo%|NZCBc;~SWjB8k1y9LZp*OQ4{tJbB{d*5fTR4CJ_FC9P# z@Due&bODw7GiR}-V6D82ws(nWt@~W3rJ9rrwNu%4NT4MRyPIbt0Srs8VgR&hQ ztHZ1R@$vHA-@m{0?&tCQv0?GMr7-pGPhf?I!{q^|!5#Wt`P`%&VzixRr<-J-xVgUO7?jZUfJHPLN)BX2* zC3=7_*&Q`*wteezPq*H0Tlf245>@QaL@AGe?cS%>I9ApMHL_Mo{)v4`+fA|$u=U}( zYc19^wqFaUv>2ZsDs00jdpEt-BUTwjr9S>^0mZ-7!?s_h?_7et!1i}uq8+elt@je+ z?RI0^Ha>s;+0-73_94Za474u!BcAC?QP}j*M(Rzc5+}nt$9)@G+;hEP8Wxp z99Sg+E#BbgiK*3{#!`V?bLaOON-JWO;5FI`9m`mYt_@A0A+`)_%q%hWc}SGyoOR?X z)v}lxv1(GvY%xo}SJrr^@7KT8E>xok{=^TT{=l{^eEIsBts5t%+K87JyM(g&q{du6VgCCALB?iPnSbF>x3a z+Zx4|pjQBE5wmZl6v0m@;@(&rdu3Y!jJ#I?fSv_wcpou(RG3B7C+5WUcEedmDUn*_ zoLdcgjkF48Rd_3uPOUt(M3U)r(v*0;-S~RF^5yNVt5OOOUbl^9i==fUt(BU4^|xot z0b14M1aZAn7-~}})1V}3i`|erh~#$dbTCzMP9b^?nOYLcdd_Ra*+DA>Yvg!u*DJYJ zw$v%Ewe6Y5;kANR)ZXV>Yn4DxX&NFNBg&FS0(}3M*>a`&f-z30DIKKi5imBf zC=mOvPJyj;+(_aNt1a3(TFZSR>r|~$dSyp~dpT#lqN~L+Ag6+N>;g&7>Rs8+Xs}jP zRBJ(0#A;+Wlk-3=NT~(P8q&omR&4sD~a0VkYtGat+km4Dn(;a7+=~7*~R&XRQtb3uXD`}dT zr-fE@9td7Y-m9^>K*>ArWjF6ORaXr`!AL1p$1gGJi8}#^PSn*Bdl84X1V^Kpx8^h@ zZp+N=WjXrcoa+Rm`o^S5jVaCe5PzEN{@?%i@7CYu^&SeU+MDbZ4ZKC~NKu0!F9TnU zAk4C@Ud2BU8z*S=?x-eM<%{(o9+R8)ybU9A*EPKI-s4-NImhVbYL-boGvYR;T%^=T zZDC~J2VL&$d6A3Q3{OGq$kcw!Mt>Fnf7VZN1V@*E{)xGBrScqwfy?>_$hhp<85FxC z%RMsSLpm&G8J{`Vfw>yf#(*9e#QTyP}zei?w|;^Ya{( zNDYwX1Z@7-fNcbxXP|q^lINyv7-yTv5&7!+^};BC7qm?y`eWWyx~IlfE<{9SZW#^s zV#<}`y#4LG53iKSzXEJe6|yIEE*H>tUD5Mr&f?F74og4maelRY>;sbz>pv@<<0tW7|b}a)7S!UON>Zua&l;{CK5F z9u!Cs>mNJE%~Q5Nn0<~AohLdS*AGf$IPG;DCxuchIWnr(m^jj@2q{O>{21TldPiQb z>GKtrPu@R&l26_}$L5X@03MIWQT`XvUX#OLAZc%#I05UAsio3#RmH{gnyU}U7*vA8 ziKkl-i0ON+ z6%}E~s;ue6(YyNXTX_ z5=l$IC$IbDp*uBPj?-jgrA|_{H_g0Hk#*PJqfWOzK&RPbvCa|WV(%3m`{*{T%-!n) z)6WcO&Yf*_gA;;7!ApuvQ)Ehkya_=% zfrjrD-wU3ClZtbYoRETJnIbQ@8R?Ch^}GbHmFH^DM6})z4bCl*V--R5K`PqHC*Crf zx|6+XK<>SmYG*K|(yG&&c{DmPVW6PkC+GY$CH}wuKmX3M%q-Kylp?`Hih*VB%u{EX z1Ir?izy-ngVZwY0Ig9|O_mLp17WgQ|`N+iD{C!S~I?myO#@19Vl7yh5Qa~S><~E4r zI({KyW9Cq)J*!66>B8Z=W!df#B9Dyo8IQY5k;8%#o`dtxdUL>nuQ3E-6}rpc#$Wmo z%wNI{3uHK|J)8jLvd!_kdLxbday0du8F%ZnrnWQyV!&Oiv1bBE+Y?0XPA*_?FaxTo z+2)+d))RBGZ~BFTrHME(0EmG#*W4jYHnQu(-|9R`=RbY?-R8CdKaSHl`qM=F-hB+j zIVfx9C6R84FzehKlJ z$CXZTT1AuE_1sl?0tGPWse#}Xu*EQvtT6I2`qHZZXbBpi$hm$wr~WuM($90zE-|#m z7FMNe8fT2h+vRTlhGSF_JRa{(77>=)!o19c z#UoMJ*22DNK<%8;6co9H?!Q~qFura_tOhJ+o53X}IL7_e^z+4Nz2 zf8TgKG&q>%V0>OpF|?vLrOIv#+XgXu(xjO%CxL0wzOytfxUe9i)TFXyy*Q5*@kZP1 zg8hCtZh51$nQ4CI%hwlDh=6CF;g*H!B3-;n!Iq7!WbW&OtyZc) zkw$S4k_m-?8ij|Bi=w_~9x9E}6tuaZhK>x{lR%miFRw4uAC*Ub47_tZe7QDqX)2TL zJq>;3T&TqWyToHa*>|lft!rUjGm|)G>Fj%9-?U=Y51L_RT{j+&hxRWOQ+flM2+e6f z)%~uCihVP4W20(`b2iCiA{%HB5rP4-VuOZdU}aQ8v@)OqJcZE*7pgx5YX-1Xvuj;P z^m^NrQY_dMybsLtNrhCPck;TA>QvJJwbsToVIV*Uw0+Mww;hAowyCn~W7|wFeWjL6 z@PS1F#j1NL=p_IC$dvLFhbP z?HfJ>=4HW&*FH)uw<1oAi>?#a5R#~+ux%CTO5LqNJ@nEPxVENP!@4O*e(jgohI zia3%cpPZ*P@J$spL#^C%C6{WGpf*j5RY=Bo6%5?b2L)5Fn*(Yoq)vfLE zU`Z3fJED&S7fCVDYGYo^GjmmQ>edvoq>AnAdsN$q_W`4LH{GSIaf>e?|d=1U2Ho>-0Vt z3h)t(**Wc&2)Y8MGXlPR{%1e86M$ac`wN=eGhn-H;{w!9Kw*LBhb@kC*1Cy*|nV8x&K<{Vbue5T|L)}k0d;E0b&kR3L=eLb{q=R^` z7JiJ-jgdV$=vY3epv^o-(i|?YNSakdDW*tB=_1&2_WWV<*8$XyQqMS_f3;jM(%=1@ zoDkrGS+6H;fYvM6I?ltfx##}4OFj8geYmcqfB1QP8Z!%r zBB@@Nc7@lMFL(adJ#l<&?DO;eVMG!gj}4@Kte*7?I6EZzpD2-)AwqJkrd`M2UkQth zYPz7UFu{9bh(}KvqVd~E27XKu0Vln9j7K&fXtnKn0si__{p$U{^HlxSI>S)K^WL*8 z3*P(FMZ8u7Q91F}cz@j4_Z{yvTR!fJZssw)bb8S;C{Dr6x@JY?wcC8AL7Wqz_D*lr zdeS;G9q~ewrVV~U5iu5A?c2sfRLQO8V!Wa8(03w%6arOj-tQXt1S@}fJPvI(bVjYI ztrA=ydZh*`IMo}Vw~=kjCe7a2w(U5D>myT2XPN@H<)*-5+cii{k(^=MvsPe4vwqG6 z^@JiYO^GSJkfs?mGV*%ko6SM9;Gp(GuELgA-XHH;oe8R%H3EV`1Mo58W2APqONcRP zuZ!=PN3+U(*ud&SAf!p<`}YRXGRUFRLL!{!%5r6nDgvg z=Rg`_B*tXCbgH|5oveN{56^a+c*~H)=CIJ`e-BEG_ z>(84-?E-q&q>x}IM8x_JHNm9RZjGY)5FlusRti3vVS5K>fk>r8)qp&Bp#@Ly&cr`J zq^mOB2s{OXc_Qj$RqVdi%AH;(rH`vWj8`uuyQYV^r}wnl$UTE7*cp8L!#75>|0_xjca_F2qDJ*&qTG687Z8*Ws^gJTd3(3YwD&-_%CN9*f!ej-we_mw ze(wihL-hH(-`A%JZ(TP)@LjX9Q;KIb!+NJ=Bv3|Ray<7YGGw$QdNsesYSwC};#u!! zn4}ro%S$dV&gz&Gp^X5-g1Kv~_8bDsx zqKk&E{qo}al1p{djq9i9?Fb0HLxS#)AJ^5J3!3f!xGoGjv+XOrQ@cBWz^8!CDq}H3 zHG#iP%uCXFbUFcBN|9(uv?svkP9YTMPB44T{QsThr~BcGz>c3!5Y+}?>qp&24{UJi zfF>j0(7RZUHD0zgvY*Em#=qC3!sUMb2wa}_Uu@jhY6+lozl=bCjNQ=MDMIp5%;He& z^vdiA{sI!NfbAkkGZJ&>vn6VYZ~<&1&gi4+$Mt!4mxRFeIhV7qzMmktUp{-Vm!v6h zvtHw)%dJ26sXePLo|pSb5%qBokEDlP50T^Y{`8sA>((spH)^Dc{a8$UBuYl&>zNAq z5wLZX(yYnN6RZWJJ`O4V;4gH@0ocH(`(l*oUkk)MgYPjmJ>~L#x%@JDbsPi7^YGbs zJ{yP6E295~A#W-o?E7x?GgV><-s5oWtBQF%)(5pz=6TkWAsz|JrLDE{cz>v3;Jbt5 zD0`>uoxDTcJ2h)%ZdqpHq!}W*XT9Iqx1BU494LV6nfW%8CZ!?x29IJK%VEQD3;;HN(G*K{o{*bYsx|v?e^(ohln*4X#_>cz?We zf85#gZlWq$Q4?`-`KCSdnF*%fkq5M4BdHJv~uLUZlNc9v@XdpJw+s3K^S zh6I?F#49i4+IV~1^;}{S@7u0YuiX^1ELa*%pCAWSRV#1RlsG4R6BTf0T6A7cTCfSbEraNRw|qNv3Ub*ncm>r*T6K*)ZAzV^5en2ZIrBuln==^%hv0| z@0=q|6EOsxG^>gslv0=`4Kj86*|6cv^76vV*RNCqg>UbxdM(yUFO_LZ%xU6wn^~6G zDsPoi8{#9*bz+Af_d7ox52dS!m~?NaWldy+5Rs@oMdRG+esn?%Ow+_XFD$d(i_8n{ zBsjG*$k|b>my_iI<_ctDo2UF7L@MT$u!Lv*=P8_XOa_cP1 zSH8TyGH6%xq(pimX=S?P z%(hj&f6s?KgL8t98l-~u>bd5qrE-6~KTUV8cib`AH-bYw@~kh#d+q;FRV)jb#zbk^ zUo0U)Ycxjx1sa^xQ~IAiys$gDsRv9#Lt$e&-VfH&#IWMo{u4o?)DH!!U9T7u8w`a21oErS2}vx z>>6t@H!N8+tQ`BGfpgO$=Ag$|BG-1@D3t0U=$ul+Y;U_Olv`ace&J@%{p+jnDUySiGDtc)HJiy`FLW`g3Tl9odC}YD=*Uw5iS=y=%Mv ztwpVbjXaw})dBZClk1LD4@LXedR0-0TDk=@&|0DQV3{jn6B(lb-2gyonVJJF=;RZ; zR-cApts4)%vpo2qSC}m87^3q0Mo}l6btyPo# zeupm9dQv347pCdP?e@y;*#xH(UF(%xGr0s@Qw5xAv@~%Zmm=K<_9nc)KR`B`B$gTO?>p<7=}vo4+H`~7 zN%NxMF-8a;i5_W=DxD^UAYOajJPa=0nIi-hmvaSle4UN^BS+BqN&@e|Dii*mOIuq_Itw0BJ> z`BH}Y>&V_~PhTxs9jjGMK1UDIFn5em2clup>YXRXNh`)u3BiVaAGPve!KQP1FM3l_ zR3)}R-nDm5+qXm~2pVaEj@Rl?*6IhMiiEjTcI%0AA>yOA1gzN?l%jpAqO`)+O-#cJ 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≀=25geY?Vjirb#r~E8Q12xKZi<0S#q#Y$v&IWJ(%*an2ZH ze;add*cb`r)%XBC=vcM~9B}laYg^K27be=7pntusf8po&T>HY$e$IQ}hx#z%)%#T+f4^E|22&uCzj*E=tQ8~e>>wi|2E+N^>+ z+pR9_BUAAjG>=Nect5Z;nZ_7DinunD9#gtJ&k(bPm1oqNv2U>-(;{ViCIdQ897Ex}J_sfJ;wK6Ezb#T7r z8W;=B$mANL$68b(cRzp7Mcl@8t=MJK6odj6ty~9Z@KJn4Vz2~fF>0)MnmpbbQj;Ly z{nHZ`%hTf%=ktkLGOcEuksc>^3Iuzi+*ex4oKC_&r&nH{f9B!gfy?F06ou*&9OQIo zicX~VeISL%{r1eu%L}K|nbYY^Ynl7sEZA9J~q`bgyzt6o@h-3K!SBrLG_N_MRBnAEY+k| z#Gw6tqt;Gd6Y0KkyWYvEaf%m$k9ZrI!-ZNFp>lVJHAuzXb*3nlr5?c;Q8w&7^ZfEm zPK6jnT*NuUupQ~G3GJmfOcyFpEmHAnEMPJ*hAn6m#zCbNQDqgQ^M-e$=RoMCwKURN zG(pld;pA8rN2y6H6VwNAxr?#A+}CoyIO}N5kk*cK1ov^_Z!-={nIqusLu(iJg*jm$!^ydNp9w{CufaW#zajP~RiylW1 z_~z60fd4hn_~K^v&pTGqK<2-S@PXUQjj0quYbd?okinMYJQgMP zphaHuS#@Kpw7ogdE!Doga6A5Aih;g#7QX)a@!fC0^j39xow)uQs2lOd{;?x)AAMF1 zF)u!XEd8-6$YFF2KlE~ev>F6I!+|pRd9Tmj^R@eIDGhTRquIanNNu!Q-TCbNE66g& zYaso31icSKt)_k9MBD9rj_YR*afMLUq}zQH%PM8>!X`riJg(l++@u=|?-=v$&% z9`5^CGH-`jJH8zdA+)}^z)Nhp(IX98ub~X_wgbtnhv`5u?i@VL6fBO!bnjaXvEP#o z5e;ekbNZhB_pa)_!dPil7)M?0u4);-w=I$0w1QN&-{rZi#gFm2+^Y1Bx82KD#6#Yz zSK5WkJ}hZEr!EJ~wE$dQC^AwADH! zRwZ^v0Jr!j?^IIRf2|CUuiPe&zXI|!U;X0?e;*%~eeaYy?Z1j0ZV(eD096nOw+{UgY=-3nziDV58x=gnxOX#sG@$OJzqM?goY>Jc|OfL zDGiQvV_g@1`l)OHZ9dJ6Nkyu4lGS%kCO~VQm>YYqRWiw}``|U{wpRwnjjngWb`4&0 zl+AYY58t$7Wv-O+suyioAb{Ki$BLZyp5VRoveZhPCg#)WvxU_

~LEf@aOwsdCZy8)BvSvq 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 HScm-&_m*ym literal 0 HcmV?d00001 diff --git a/test/appium/views/home_view.py b/test/appium/views/home_view.py index 2785cd1d6e66..7298834c243e 100644 --- a/test/appium/views/home_view.py +++ b/test/appium/views/home_view.py @@ -490,25 +490,11 @@ def get_contact_rows_count(self): def get_link_to_profile(self): self.driver.info('Getting profile link via share profile QR') self.show_qr_code_button.click() - try: - element = self.link_to_profile_button.find_element() - except NoSuchElementException: - element = None - pass self.share_profile_tab_button.click() - if element: - self.wait_for_staleness_of_element(element) - for _ in range(3): - try: - self.link_to_profile_button.click() - link_to_profile = self.sharing_text_native.text - break - except NoSuchElementException: - link_to_profile = "" - continue + self.link_to_profile_text.click() + link_to_profile = self.driver.get_clipboard_text() if not link_to_profile: raise NoSuchElementException("Can't get link to profile") - self.click_system_back_button() return link_to_profile def get_public_key(self): From ce1d2c4ed8d70147fc7ef4e938ec642fa3de5d15 Mon Sep 17 00:00:00 2001 From: Siddarth Kumar Date: Tue, 7 Jan 2025 15:45:54 +0530 Subject: [PATCH 03/15] android: Kotlinify push notifications module (#21881) --- .../pushnotifications/ForegroundService.java | 109 --- .../pushnotifications/ForegroundService.kt | 122 +++ .../pushnotifications/PushNotification.java | 146 --- .../pushnotifications/PushNotification.kt | 118 +++ .../PushNotificationActions.java | 93 -- .../PushNotificationActions.kt | 100 ++ .../PushNotificationHelper.java | 890 ------------------ .../PushNotificationHelper.kt | 750 +++++++++++++++ .../PushNotificationJsDelivery.java | 86 -- .../PushNotificationJsDelivery.kt | 93 ++ .../PushNotificationPackage.java | 27 - .../PushNotificationPackage.kt | 24 + .../PushNotificationPicturesAggregator.java | 136 --- .../PushNotificationPicturesAggregator.kt | 109 +++ .../PushNotificationHelperTest.java | 54 -- .../PushNotificationHelperTest.kt | 49 + 16 files changed, 1365 insertions(+), 1541 deletions(-) delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/ForegroundService.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/ForegroundService.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotification.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotification.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationActions.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationActions.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationHelper.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationHelper.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationJsDelivery.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationJsDelivery.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPackage.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPackage.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPicturesAggregator.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPicturesAggregator.kt delete mode 100644 modules/react-native-status/android/src/test/java/im/status/ethereum/pushnotifications/PushNotificationHelperTest.java create mode 100644 modules/react-native-status/android/src/test/java/im/status/ethereum/pushnotifications/PushNotificationHelperTest.kt diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/ForegroundService.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/ForegroundService.java deleted file mode 100644 index 80002f20f12c..000000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/ForegroundService.java +++ /dev/null @@ -1,109 +0,0 @@ -package im.status.ethereum.pushnotifications; - -import android.content.Context; -import android.content.Intent; -import android.app.Service; -import android.content.pm.ServiceInfo; -import android.os.IBinder; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.provider.Settings; - -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; - -import android.os.Build; -import im.status.ethereum.module.R; - -public class ForegroundService extends Service { - private static final String CHANNEL_ID = "status-service"; - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public int onStartCommand(Intent i, int flags, int startId) { - // NOTE: recent versions of Android require the service to display - // a sticky notification to inform the user that the service is running - Context context = getApplicationContext(); - // Create the NotificationChannel, but only on API 26+ because - // the NotificationChannel class is new and not in the support library - - Intent intent = null; - String notificationContentText = null; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationManager notificationManager = - context.getSystemService(NotificationManager.class); - NotificationChannel channel = new NotificationChannel(CHANNEL_ID, - context.getResources().getString(R.string.status_service), - NotificationManager.IMPORTANCE_HIGH); - channel.setShowBadge(false); - notificationManager.createNotificationChannel(channel); - - // Create intent that takes the user to the notification channel settings so they can hide it - - intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); - intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); - intent.putExtra(Settings.EXTRA_CHANNEL_ID, CHANNEL_ID); - - notificationContentText = context.getResources().getString(R.string.tap_to_hide_notification); - - } else { - - // For older versions of android intent takes the user to the Status app - - Class intentClass; - String packageName = context.getPackageName(); - Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); - String className = launchIntent.getComponent().getClassName(); - try { - intentClass = Class.forName(className); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - return 0; - } - - intent = new Intent(context, intentClass); - intent.addCategory(Intent.CATEGORY_BROWSABLE); - intent.setAction(Intent.ACTION_VIEW); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - - notificationContentText = context.getResources().getString(R.string.keep_status_running); - - } - - - - PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); - Intent stopIntent = new Intent(PushNotificationHelper.ACTION_TAP_STOP); - PendingIntent stopPendingIntent = PendingIntent.getBroadcast(context, 0, stopIntent, - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); - - Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID) - .setSmallIcon(R.drawable.ic_stat_notify_status) - .setContentTitle(context.getResources().getString(R.string.background_service_opened)) - .setContentText(notificationContentText) - .setPriority(NotificationCompat.PRIORITY_HIGH) - .setCategory(NotificationCompat.CATEGORY_MESSAGE) - .setContentIntent(pendingIntent) - .setNumber(0) - .addAction(R.drawable.ic_stat_notify_status, - context.getResources().getString(R.string.stop), - stopPendingIntent) - .build(); - - // the id of the foreground notification MUST NOT be 0 - if (Build.VERSION.SDK_INT >= 33) { - startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE); - } else { - startForeground(1, notification); - } - - return START_STICKY; - } -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/ForegroundService.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/ForegroundService.kt new file mode 100644 index 000000000000..753a241940e6 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/ForegroundService.kt @@ -0,0 +1,122 @@ +package im.status.ethereum.pushnotifications + +import android.content.Context +import android.content.Intent +import android.app.Service +import android.content.pm.ServiceInfo +import android.os.IBinder +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.provider.Settings +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import android.os.Build +import im.status.ethereum.module.R + +class ForegroundService : Service() { + companion object { + private const val CHANNEL_ID = "status-service" + } + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun onStartCommand(i: Intent?, flags: Int, startId: Int): Int { + // NOTE: recent versions of Android require the service to display + // a sticky notification to inform the user that the service is running + val context = applicationContext + // Create the NotificationChannel, but only on API 26+ because + // the NotificationChannel class is new and not in the support library + + // Create notification channel for Android O and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val notificationManager = context.getSystemService(NotificationManager::class.java) + val channel = NotificationChannel( + CHANNEL_ID, + context.resources.getString(R.string.status_service), + NotificationManager.IMPORTANCE_HIGH + ).apply { + setShowBadge(false) + } + notificationManager.createNotificationChannel(channel) + } + + // Initialize intent and notification text based on Android version + val notificationIntent = createNotificationIntent(context) + val notificationText = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.resources.getString(R.string.tap_to_hide_notification) + } else { + context.resources.getString(R.string.keep_status_running) + } + + val pendingIntent = PendingIntent.getActivity( + this, + 0, + notificationIntent, + PendingIntent.FLAG_IMMUTABLE + ) + + val stopIntent = Intent(PushNotificationHelper.ACTION_TAP_STOP) + val stopPendingIntent = PendingIntent.getBroadcast( + context, + 0, + stopIntent, + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + + val notification = NotificationCompat.Builder(context, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_stat_notify_status) + .setContentTitle(context.resources.getString(R.string.background_service_opened)) + .setContentText(notificationText) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setCategory(NotificationCompat.CATEGORY_MESSAGE) + .setContentIntent(pendingIntent) + .setNumber(0) + .addAction( + R.drawable.ic_stat_notify_status, + context.resources.getString(R.string.stop), + stopPendingIntent + ) + .build() + + // the id of the foreground notification MUST NOT be 0 + if (Build.VERSION.SDK_INT >= 33) { + startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE) + } else { + startForeground(1, notification) + } + + return START_STICKY + } + + private fun createNotificationIntent(context: Context): Intent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // Create intent that takes the user to the notification channel settings + Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, packageName) + putExtra(Settings.EXTRA_CHANNEL_ID, CHANNEL_ID) + } + } else { + // For older versions of android, intent takes the user to the Status app + val packageName = context.packageName + val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName) + val className = launchIntent?.component?.className + + try { + val intentClass = Class.forName(className!!) + Intent(context, intentClass).apply { + addCategory(Intent.CATEGORY_BROWSABLE) + action = Intent.ACTION_VIEW + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + } + } catch (e: ClassNotFoundException) { + e.printStackTrace() + // Return an empty intent as fallback + Intent() + } + } + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotification.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotification.java deleted file mode 100644 index 02ab837c9acf..000000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotification.java +++ /dev/null @@ -1,146 +0,0 @@ -package im.status.ethereum.pushnotifications; - -import android.app.Activity; -import android.app.Application; -import android.app.NotificationManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.core.app.NotificationManagerCompat; - -import java.security.SecureRandom; - -import com.facebook.react.bridge.ActivityEventListener; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.WritableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; -import android.util.Log; - -import im.status.ethereum.pushnotifications.PushNotificationJsDelivery; - -public class PushNotification extends ReactContextBaseJavaModule implements ActivityEventListener { - public static final String LOG_TAG = "PushNotification"; - - private final SecureRandom mRandomNumberGenerator = new SecureRandom(); - private PushNotificationHelper pushNotificationHelper; - private PushNotificationJsDelivery delivery; - private ReactApplicationContext reactContext; - private boolean started; - - public PushNotification(ReactApplicationContext reactContext) { - super(reactContext); - this.reactContext = reactContext; - reactContext.addActivityEventListener(this); - Application applicationContext = (Application) reactContext.getApplicationContext(); - - IntentFilter intentFilter = new IntentFilter(); - pushNotificationHelper = new PushNotificationHelper(applicationContext, intentFilter); - - delivery = new PushNotificationJsDelivery(reactContext); - } - - @Override - public String getName() { - return "PushNotification"; - } - - // removed @Override temporarily just to get it working on different versions of RN - public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { - onActivityResult(requestCode, resultCode, data); - } - - // removed @Override temporarily just to get it working on different versions of RN - public void onActivityResult(int requestCode, int resultCode, Intent data) { - // Ignored, required to implement ActivityEventListener for RN 0.33 - } - - private Bundle getBundleFromIntent(Intent intent) { - Bundle bundle = null; - if (intent.hasExtra("notification")) { - bundle = intent.getBundleExtra("notification"); - } else if (intent.hasExtra("google.message_id")) { - bundle = new Bundle(); - - bundle.putBundle("data", intent.getExtras()); - } - - if(null != bundle && !bundle.getBoolean("foreground", false) && !bundle.containsKey("userInteraction")) { - bundle.putBoolean("userInteraction", true); - } - - return bundle; - } - - @Override - public void onNewIntent(Intent intent) { - Bundle bundle = this.getBundleFromIntent(intent); - if (bundle != null) { - delivery.notifyNotification(bundle); - } - } - - @ReactMethod - /** - * Creates a channel if it does not already exist. Returns whether the channel was created. - */ - public void createChannel(ReadableMap channelInfo, Callback callback) { - boolean created = pushNotificationHelper.createChannel(channelInfo); - - if(callback != null) { - callback.invoke(created); - } - } - - @ReactMethod - public void presentLocalNotification(ReadableMap details) { - if (!this.started) { - return; - } - - Bundle bundle = Arguments.toBundle(details); - // If notification ID is not provided by the user, generate one at random - if (bundle.getString("id") == null) { - bundle.putString("id", String.valueOf(mRandomNumberGenerator.nextInt())); - } - - pushNotificationHelper.sendToNotificationCentre(bundle); - } - - @ReactMethod - public void clearMessageNotifications(String conversationId) { - if (this.started) { - pushNotificationHelper.clearMessageNotifications(conversationId); - } - } - - @ReactMethod - public void clearAllMessageNotifications() { - pushNotificationHelper.clearAllMessageNotifications(); - } - - @ReactMethod - public void enableNotifications() { - this.started = true; - this.pushNotificationHelper.start(); - } - - @ReactMethod - public void disableNotifications() { - if (this.started) { - this.started = false; - this.pushNotificationHelper.stop(); - } - } -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotification.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotification.kt new file mode 100644 index 000000000000..918e088eb475 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotification.kt @@ -0,0 +1,118 @@ +package im.status.ethereum.pushnotifications + +import android.app.Activity +import android.app.Application +import android.app.NotificationManager +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.Bundle +import android.util.Log +import androidx.annotation.NonNull +import androidx.core.app.NotificationManagerCompat +import com.facebook.react.bridge.* +import im.status.ethereum.pushnotifications.PushNotificationJsDelivery +import java.security.SecureRandom + +class PushNotification(reactContext: ReactApplicationContext) : + ReactContextBaseJavaModule(reactContext), ActivityEventListener { + + companion object { + const val LOG_TAG = "PushNotification" + } + + private val mRandomNumberGenerator = SecureRandom() + private val pushNotificationHelper: PushNotificationHelper + private val delivery: PushNotificationJsDelivery + private val reactContext: ReactApplicationContext = reactContext + private var started: Boolean = false + + init { + reactContext.addActivityEventListener(this) + val applicationContext = reactContext.applicationContext as Application + + val intentFilter = IntentFilter() + pushNotificationHelper = PushNotificationHelper(applicationContext, intentFilter) + + delivery = PushNotificationJsDelivery(reactContext) + } + + override fun getName(): String = "PushNotification" + + // Primary implementation of ActivityEventListener interface + override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) { + // Call the helper method with the correct parameter order + handleActivityResult(requestCode, resultCode, data) + } + + // Private helper method for handling activity results + private fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + // Ignored, required to implement ActivityEventListener for RN 0.33 + } + + private fun getBundleFromIntent(intent: Intent): Bundle? { + return when { + intent.hasExtra("notification") -> intent.getBundleExtra("notification") + intent.hasExtra("google.message_id") -> Bundle().apply { + putBundle("data", intent.extras) + } + else -> null + }?.apply { + if (!getBoolean("foreground", false) && !containsKey("userInteraction")) { + putBoolean("userInteraction", true) + } + } + } + + override fun onNewIntent(intent: Intent) { + getBundleFromIntent(intent)?.let { bundle -> + delivery.notifyNotification(bundle) + } + } + + @ReactMethod + fun createChannel(channelInfo: ReadableMap, callback: Callback?) { + val created = pushNotificationHelper.createChannel(channelInfo) + callback?.invoke(created) + } + + @ReactMethod + fun presentLocalNotification(details: ReadableMap) { + if (!started) return + + Arguments.toBundle(details)?.apply { + // If notification ID is not provided by the user, generate one at random + if (getString("id") == null) { + putString("id", mRandomNumberGenerator.nextInt().toString()) + } + pushNotificationHelper.sendToNotificationCentre(this) + } + } + + @ReactMethod + fun clearMessageNotifications(conversationId: String) { + if (started) { + pushNotificationHelper.clearMessageNotifications(conversationId) + } + } + + @ReactMethod + fun clearAllMessageNotifications() { + pushNotificationHelper.clearAllMessageNotifications() + } + + @ReactMethod + fun enableNotifications() { + started = true + pushNotificationHelper.start() + } + + @ReactMethod + fun disableNotifications() { + if (started) { + started = false + pushNotificationHelper.stop() + } + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationActions.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationActions.java deleted file mode 100644 index 3a9a3e570221..000000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationActions.java +++ /dev/null @@ -1,93 +0,0 @@ -package im.status.ethereum.pushnotifications; - -import android.os.Build; -import android.app.Application; -import android.app.NotificationManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; - -import com.facebook.react.ReactApplication; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.bridge.ReactContext; - - -import im.status.ethereum.pushnotifications.PushNotificationJsDelivery; -import static im.status.ethereum.pushnotifications.PushNotification.LOG_TAG; - -public class PushNotificationActions extends BroadcastReceiver { - @Override - public void onReceive(final Context context, Intent intent) { - String intentActionPrefix = context.getPackageName() + ".ACTION_"; - - Log.i(LOG_TAG, "PushNotificationBootEventReceiver loading scheduled notifications"); - - if (null == intent.getAction() || !intent.getAction().startsWith(intentActionPrefix)) { - return; - } - - final Bundle bundle = intent.getBundleExtra("notification"); - - // Dismiss the notification popup. - NotificationManager manager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); - int notificationID = Integer.parseInt(bundle.getString("id")); - - boolean autoCancel = bundle.getBoolean("autoCancel", true); - - if(autoCancel) { - if (bundle.containsKey("tag")) { - String tag = bundle.getString("tag"); - manager.cancel(tag, notificationID); - } else { - manager.cancel(notificationID); - } - } - - boolean invokeApp = bundle.getBoolean("invokeApp", true); - - // Notify the action. - if(invokeApp) { - - IntentFilter intentFilter = new IntentFilter(); - PushNotificationHelper helper = new PushNotificationHelper((Application) context.getApplicationContext(), intentFilter); - - helper.invokeApp(bundle); - } else { - - // We need to run this on the main thread, as the React code assumes that is true. - // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers: - // "Can't create handler inside thread that has not called Looper.prepare()" - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - public void run() { - // Construct and load our normal React JS code bundle - final ReactInstanceManager mReactInstanceManager = ((ReactApplication) context.getApplicationContext()).getReactNativeHost().getReactInstanceManager(); - ReactContext context = mReactInstanceManager.getCurrentReactContext(); - PushNotificationJsDelivery delivery = new PushNotificationJsDelivery(context); - // If it's constructed, send a notification - if (context != null) { - delivery.notifyNotificationAction(bundle); - } else { - // Otherwise wait for construction, then send the notification - mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { - public void onReactContextInitialized(ReactContext context) { - PushNotificationJsDelivery delivery = new PushNotificationJsDelivery(context); - delivery.notifyNotificationAction(bundle); - mReactInstanceManager.removeReactInstanceEventListener(this); - } - }); - if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { - // Construct it in the background - mReactInstanceManager.createReactContextInBackground(); - } - } - } - }); - } - } -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationActions.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationActions.kt new file mode 100644 index 000000000000..9bcbc3dae710 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationActions.kt @@ -0,0 +1,100 @@ +package im.status.ethereum.pushnotifications + +import android.os.Build +import android.app.Application +import android.app.NotificationManager +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.util.Log +import com.facebook.react.ReactApplication +import com.facebook.react.ReactInstanceManager +import com.facebook.react.bridge.ReactContext +import im.status.ethereum.pushnotifications.PushNotificationJsDelivery +import im.status.ethereum.pushnotifications.PushNotification.Companion.LOG_TAG + +/** + * BroadcastReceiver responsible for handling push notification actions. + * This class processes notification interactions and manages their lifecycle. + */ +class PushNotificationActions : BroadcastReceiver() { + + override fun onReceive(context: Context, intent: Intent) { + val intentActionPrefix = "${context.packageName}.ACTION_" + + Log.i(LOG_TAG, "PushNotificationBootEventReceiver loading scheduled notifications") + + if (intent.action == null || !intent.action!!.startsWith(intentActionPrefix)) { + return + } + + val bundle = intent.getBundleExtra("notification") ?: return + + val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + val notificationID = bundle.getString("id")?.toInt() ?: return + + // Dismiss the notification popup. + val autoCancel = bundle.getBoolean("autoCancel", true) + if (autoCancel) { + bundle.getString("tag")?.let { tag -> + manager.cancel(tag, notificationID) + } ?: run { + manager.cancel(notificationID) + } + } + + // Notify the action. + val invokeApp = bundle.getBoolean("invokeApp", true) + + if (invokeApp) { + val intentFilter = IntentFilter() + val helper = PushNotificationHelper( + context.applicationContext as Application, + intentFilter + ) + helper.invokeApp(bundle) + } else { + // We need to run this on the main thread, as the React code assumes that is true. + // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers: + // "Can't create handler inside thread that has not called Looper.prepare()" + Handler(Looper.getMainLooper()).post { + // Construct and load our normal React JS code bundle + val reactInstanceManager = (context.applicationContext as ReactApplication) + .reactNativeHost + .reactInstanceManager + + val currentContext = reactInstanceManager.currentReactContext + + when { + // If context exists, deliver notification immediately + currentContext != null -> { + PushNotificationJsDelivery(currentContext) + .notifyNotificationAction(bundle) + } + // Otherwise wait for construction, then send the notification + else -> { + val listener = object : ReactInstanceManager.ReactInstanceEventListener { + override fun onReactContextInitialized(reactContext: ReactContext) { + PushNotificationJsDelivery(reactContext) + .notifyNotificationAction(bundle) + reactInstanceManager.removeReactInstanceEventListener(this) + } + } + + // Add the listener and create context if needed + reactInstanceManager.addReactInstanceEventListener(listener) + if (!reactInstanceManager.hasStartedCreatingInitialContext()) { + // Construct it in the background + reactInstanceManager.createReactContextInBackground() + } + } + } + } + } + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationHelper.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationHelper.java deleted file mode 100644 index 899f8ab96b78..000000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationHelper.java +++ /dev/null @@ -1,890 +0,0 @@ -// https://github.com/zo0r/react-native-push-notification/blob/bedc8f646aab67d594f291449fbfa24e07b64fe8/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java Copy-Paste with removed firebase -package im.status.ethereum.pushnotifications; - -import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; -import android.app.AlarmManager; -import android.app.Application; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.BroadcastReceiver; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.RectF; -import android.media.AudioAttributes; -import android.media.RingtoneManager; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.service.notification.StatusBarNotification; -import android.util.Log; -import android.util.Base64; - -import androidx.annotation.RequiresApi; -import androidx.core.app.NotificationCompat; -import androidx.core.app.Person; -import androidx.core.graphics.drawable.IconCompat; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableArray; -import com.facebook.react.bridge.WritableMap; - -import org.json.JSONArray; -import org.json.JSONException; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.HashMap; -import java.util.Map; - -import im.status.ethereum.module.R; -import static im.status.ethereum.pushnotifications.PushNotification.LOG_TAG; - -public class PushNotificationHelper { - - private Context context; - - private static final long DEFAULT_VIBRATION = 300L; - private static final String CHANNEL_ID = "status-im-notifications"; - public static final String ACTION_DELETE_NOTIFICATION = "im.status.ethereum.module.DELETE_NOTIFICATION"; - public static final String ACTION_TAP_STOP = "im.status.ethereum.module.TAP_STOP"; - final int flag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_CANCEL_CURRENT; - - private NotificationManager notificationManager; - - - private HashMap persons; - private HashMap messageGroups; - - private IntentFilter intentFilter; - - public PushNotificationHelper(Application context, IntentFilter intentFilter) { - this.context = context; - this.intentFilter = intentFilter; - this.persons = new HashMap(); - this.messageGroups = new HashMap(); - this.notificationManager = context.getSystemService(NotificationManager.class); - this.registerBroadcastReceiver(); - } - - public Intent getOpenAppIntent(String deepLink) { - Class intentClass; - String packageName = context.getPackageName(); - Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); - String className = launchIntent.getComponent().getClassName(); - try { - intentClass = Class.forName(className); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - return null; - } - Intent intent = new Intent(context, intentClass); - intent.addCategory(Intent.CATEGORY_BROWSABLE); - intent.setAction(Intent.ACTION_VIEW); - //NOTE: you might wonder, why the heck did he decide to set these flags in particular. Well, - //the answer is a simple as it can get in the Android native development world. I noticed - //that my initial setup was opening the app but wasn't triggering any events on the js side, like - //the links do from the browser. So I compared both intents and noticed that the link from - //the browser produces an intent with the flag 0x14000000. I found out that it was the following - //flags in this link: - //https://stackoverflow.com/questions/52390129/android-intent-setflags-issue - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - if (deepLink != null) { - intent.setData(Uri.parse(deepLink)); - } - return intent; - } - - //NOTE: we use a dynamically created BroadcastReceiver here so that we can capture - //intents from notifications and act on them. For instance when tapping/dismissing - //a chat notification we want to clear the chat so that next messages don't show - //the messages that we have seen again - private final BroadcastReceiver notificationActionReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction() == ACTION_DELETE_NOTIFICATION) { - String groupId = intent.getExtras().getString("im.status.ethereum.groupId"); - if (groupId != null) { - cleanGroup(groupId); - } - } - if (intent.getAction() == ACTION_TAP_STOP) { - stop(); - System.exit(0); - } - Log.e(LOG_TAG, "intent received: " + intent.getAction()); - } - }; - - public void registerBroadcastReceiver() { - this.intentFilter.addAction(ACTION_DELETE_NOTIFICATION); - this.intentFilter.addAction(ACTION_TAP_STOP); - context.registerReceiver(notificationActionReceiver, this.intentFilter, Context.RECEIVER_EXPORTED); - Log.e(LOG_TAG, "Broadcast Receiver registered"); - } - - - - private NotificationManager notificationManager() { - return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - } - - public void invokeApp(Bundle bundle) { - String packageName = context.getPackageName(); - Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); - String className = launchIntent.getComponent().getClassName(); - - try { - Class activityClass = Class.forName(className); - Intent activityIntent = new Intent(context, activityClass); - - if(bundle != null) { - activityIntent.putExtra("notification", bundle); - } - - activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - context.startActivity(activityIntent); - } catch(Exception e) { - Log.e(LOG_TAG, "Class not found", e); - return; - } - } - - public void sendToNotificationCentre(final Bundle bundle) { - PushNotificationPicturesAggregator aggregator = new PushNotificationPicturesAggregator(new PushNotificationPicturesAggregator.Callback() { - public void call(Bitmap largeIconImage, Bitmap bigPictureImage) { - sendToNotificationCentreWithPicture(bundle, largeIconImage, bigPictureImage); - } - }); - - aggregator.setLargeIconUrl(context, bundle.getString("largeIconUrl")); - aggregator.setBigPictureUrl(context, bundle.getString("bigPictureUrl")); - } - - public void handleConversation(final Bundle bundle) { - if (bundle.getBoolean("deleted")){ - this.removeStatusMessage(bundle); - } else { - this.addStatusMessage(bundle); - } - } - - public void clearMessageNotifications(String conversationId) { - notificationManager.cancel(conversationId.hashCode()); - cleanGroup(conversationId); - } - - public void clearAllMessageNotifications() { - notificationManager.cancelAll(); - } - - public void sendToNotificationCentreWithPicture(final Bundle bundle, Bitmap largeIconBitmap, Bitmap bigPictureBitmap) { - - try { - Class intentClass = getMainActivityClass(); - if (intentClass == null) { - Log.e(LOG_TAG, "No activity class found for the notification"); - return; - } - - if (bundle.getBoolean("isConversation")) { - this.handleConversation(bundle); - return; - } - - if (bundle.getString("message") == null) { - // this happens when a 'data' notification is received - we do not synthesize a local notification in this case - Log.d(LOG_TAG, "Ignore this message if you sent data-only notification. Cannot send to notification centre because there is no 'message' field in: " + bundle); - return; - } - - String notificationIdString = bundle.getString("id"); - if (notificationIdString == null) { - Log.e(LOG_TAG, "No notification ID specified for the notification"); - return; - } - - Resources res = context.getResources(); - String packageName = context.getPackageName(); - - String title = bundle.getString("title"); - if (title == null) { - ApplicationInfo appInfo = context.getApplicationInfo(); - title = context.getPackageManager().getApplicationLabel(appInfo).toString(); - } - - int priority = NotificationCompat.PRIORITY_HIGH; - final String priorityString = bundle.getString("priority"); - - if (priorityString != null) { - switch (priorityString.toLowerCase()) { - case "max": - priority = NotificationCompat.PRIORITY_MAX; - break; - case "high": - priority = NotificationCompat.PRIORITY_HIGH; - break; - case "low": - priority = NotificationCompat.PRIORITY_LOW; - break; - case "min": - priority = NotificationCompat.PRIORITY_MIN; - break; - case "default": - priority = NotificationCompat.PRIORITY_DEFAULT; - break; - default: - priority = NotificationCompat.PRIORITY_HIGH; - } - } - - int visibility = NotificationCompat.VISIBILITY_PRIVATE; - final String visibilityString = bundle.getString("visibility"); - - if (visibilityString != null) { - switch (visibilityString.toLowerCase()) { - case "private": - visibility = NotificationCompat.VISIBILITY_PRIVATE; - break; - case "public": - visibility = NotificationCompat.VISIBILITY_PUBLIC; - break; - case "secret": - visibility = NotificationCompat.VISIBILITY_SECRET; - break; - default: - visibility = NotificationCompat.VISIBILITY_PRIVATE; - } - } - - String channel_id = bundle.getString("channelId"); - - if(channel_id == null) { - channel_id = this.getNotificationDefaultChannelId(); - } - - NotificationCompat.Builder notification = new NotificationCompat.Builder(context, channel_id) - .setContentTitle(title) - .setTicker(bundle.getString("ticker")) - .setVisibility(visibility) - .setPriority(priority) - .setAutoCancel(bundle.getBoolean("autoCancel", true)) - .setOnlyAlertOnce(bundle.getBoolean("onlyAlertOnce", false)); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // API 24 and higher - // Restore showing timestamp on Android 7+ - // Source: https://developer.android.com/reference/android/app/Notification.Builder.html#setShowWhen(boolean) - boolean showWhen = bundle.getBoolean("showWhen", true); - - notification.setShowWhen(showWhen); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher - // Changing Default mode of notification - notification.setDefaults(Notification.DEFAULT_LIGHTS); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { // API 20 and higher - String group = bundle.getString("group"); - - if (group != null) { - notification.setGroup(group); - } - - if (bundle.containsKey("groupSummary") || bundle.getBoolean("groupSummary")) { - notification.setGroupSummary(bundle.getBoolean("groupSummary")); - } - } - - String numberString = bundle.getString("number"); - - if (numberString != null) { - notification.setNumber(Integer.parseInt(numberString)); - } - - // Small icon - int smallIconResId = 0; - - String smallIcon = bundle.getString("smallIcon"); - - if (smallIcon != null && !smallIcon.isEmpty()) { - smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName); - } else if(smallIcon == null) { - smallIconResId = res.getIdentifier("ic_stat_notify_status", "drawable", packageName); - } - - if (smallIconResId == 0) { - smallIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); - - if (smallIconResId == 0) { - smallIconResId = android.R.drawable.ic_dialog_info; - } - } - - notification.setSmallIcon(smallIconResId); - - // Large icon - if(largeIconBitmap == null) { - int largeIconResId = 0; - - String largeIcon = bundle.getString("largeIcon"); - - if (largeIcon != null && !largeIcon.isEmpty()) { - largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); - } else if(largeIcon == null) { - largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); - } - - // Before Lolipop there was no large icon for notifications. - if (largeIconResId != 0 && (largeIcon != null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) { - largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId); - } - } - - Bundle author = bundle.getBundle("notificationAuthor"); - - if (largeIconBitmap == null && author != null) { - String base64Image = author.getString("icon").split(",")[1]; - byte[] decodedString = Base64.decode(base64Image, Base64.DEFAULT); - Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); - notification.setLargeIcon(getCircleBitmap(decodedByte)); - } else if (largeIconBitmap != null){ - notification.setLargeIcon(largeIconBitmap); - } - - String message = bundle.getString("message"); - - notification.setContentText(message); - - String subText = bundle.getString("subText"); - - if (subText != null) { - notification.setSubText(subText); - } - - String bigText = bundle.getString("bigText"); - - if (bigText == null) { - bigText = message; - } - - NotificationCompat.Style style; - - if(bigPictureBitmap != null) { - style = new NotificationCompat.BigPictureStyle() - .bigPicture(bigPictureBitmap) - .setBigContentTitle(title) - .setSummaryText(message); - } else { - style = new NotificationCompat.BigTextStyle().bigText(bigText); - } - - notification.setStyle(style); - - Intent intent = new Intent(context, intentClass); - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - bundle.putBoolean("foreground", this.isApplicationInForeground()); - bundle.putBoolean("userInteraction", true); - intent.putExtra("notification", bundle); - - Uri soundUri = null; - - if (!bundle.containsKey("playSound") || bundle.getBoolean("playSound")) { - String soundName = bundle.getString("soundName"); - - if (soundName == null) { - soundName = "default"; - } - - soundUri = getSoundUri(soundName); - - notification.setSound(soundUri); - } - - if (soundUri == null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notification.setSound(null); - } - - if (bundle.containsKey("ongoing") || bundle.getBoolean("ongoing")) { - notification.setOngoing(bundle.getBoolean("ongoing")); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - notification.setCategory(NotificationCompat.CATEGORY_CALL); - - String color = bundle.getString("color"); - int defaultColor = -1; - if (color != null) { - notification.setColor(Color.parseColor(color)); - } else if (defaultColor != -1) { - notification.setColor(defaultColor); - } - } - - int notificationID = notificationIdString.hashCode(); - - notification.setContentIntent(createOnTapIntent(context, notificationID, bundle.getString("deepLink"))) - .setDeleteIntent(createOnDismissedIntent(context, notificationID, bundle.getString("deepLink"))); - - NotificationManager notificationManager = notificationManager(); - - long[] vibratePattern = new long[]{0}; - - if (!bundle.containsKey("vibrate") || bundle.getBoolean("vibrate")) { - long vibration = bundle.containsKey("vibration") ? (long) bundle.getDouble("vibration") : DEFAULT_VIBRATION; - if (vibration == 0) - vibration = DEFAULT_VIBRATION; - - vibratePattern = new long[]{0, vibration}; - - notification.setVibrate(vibratePattern); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - // Define the shortcutId - String shortcutId = bundle.getString("shortcutId"); - - if (shortcutId != null) { - notification.setShortcutId(shortcutId); - } - - Long timeoutAfter = (long) bundle.getDouble("timeoutAfter"); - - if (timeoutAfter != null && timeoutAfter >= 0) { - notification.setTimeoutAfter(timeoutAfter); - } - } - - Long when = (long) bundle.getDouble("when"); - - if (when != null && when >= 0) { - notification.setWhen(when); - } - - notification.setUsesChronometer(bundle.getBoolean("usesChronometer", false)); - notification.setChannelId(channel_id); - - JSONArray actionsArray = null; - try { - actionsArray = bundle.getString("actions") != null ? new JSONArray(bundle.getString("actions")) : null; - } catch (JSONException e) { - Log.e(LOG_TAG, "Exception while converting actions to JSON object.", e); - } - - if (actionsArray != null) { - // No icon for now. The icon value of 0 shows no icon. - int icon = 0; - - // Add button for each actions. - for (int i = 0; i < actionsArray.length(); i++) { - String action; - try { - action = actionsArray.getString(i); - } catch (JSONException e) { - Log.e(LOG_TAG, "Exception while getting action from actionsArray.", e); - continue; - } - - - Intent actionIntent = new Intent(context, PushNotificationActions.class); - actionIntent.setAction(packageName + ".ACTION_" + i); - - actionIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - - // Add "action" for later identifying which button gets pressed. - bundle.putString("action", action); - actionIntent.putExtra("notification", bundle); - actionIntent.setPackage(packageName); - - PendingIntent pendingActionIntent = PendingIntent.getBroadcast(context, notificationID, actionIntent, - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - notification.addAction(new NotificationCompat.Action.Builder(icon, action, pendingActionIntent).build()); - } else { - notification.addAction(icon, action, pendingActionIntent); - } - } - } - - - if (!(this.isApplicationInForeground() && bundle.getBoolean("ignoreInForeground"))) { - Notification info = notification.build(); - info.defaults |= Notification.DEFAULT_LIGHTS; - - if (bundle.containsKey("tag")) { - String tag = bundle.getString("tag"); - notificationManager.notify(tag, notificationID, info); - } else { - notificationManager.notify(notificationID, info); - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "failed to send push notification", e); - } - } - - private boolean checkOrCreateChannel(NotificationManager manager, String channel_id, String channel_name, String channel_description, Uri soundUri, int importance, long[] vibratePattern, boolean showBadge) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) - return false; - if (manager == null) - return false; - - NotificationChannel channel = manager.getNotificationChannel(channel_id); - - if ( - channel == null && channel_name != null && channel_description != null || - channel != null && - ( - channel_name != null && !channel.getName().equals(channel_name) || - channel_description != null && !channel.getDescription().equals(channel_description) - ) - ) { - // If channel doesn't exist create a new one. - // If channel name or description is updated then update the existing channel. - channel = new NotificationChannel(channel_id, channel_name, importance); - - channel.setDescription(channel_description); - channel.enableLights(true); - channel.enableVibration(vibratePattern != null); - channel.setVibrationPattern(vibratePattern); - channel.setShowBadge(showBadge); - - if (soundUri != null) { - AudioAttributes audioAttributes = new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .setUsage(AudioAttributes.USAGE_NOTIFICATION) - .build(); - - channel.setSound(soundUri, audioAttributes); - } else { - channel.setSound(null, null); - } - - manager.createNotificationChannel(channel); - - return true; - } - - return false; - } - - public boolean createChannel(ReadableMap channelInfo) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) - return false; - - String channelId = channelInfo.getString("channelId"); - String channelName = channelInfo.getString("channelName"); - String channelDescription = channelInfo.hasKey("channelDescription") ? channelInfo.getString("channelDescription") : ""; - String soundName = channelInfo.hasKey("soundName") ? channelInfo.getString("soundName") : "default"; - int importance = channelInfo.hasKey("importance") ? channelInfo.getInt("importance") : 4; - boolean vibrate = channelInfo.hasKey("vibrate") && channelInfo.getBoolean("vibrate"); - long[] vibratePattern = vibrate ? new long[] { DEFAULT_VIBRATION } : null; - boolean showBadge = channelInfo.hasKey("showBadge") && channelInfo.getBoolean("showBadge"); - - NotificationManager manager = notificationManager(); - - Uri soundUri = getSoundUri(soundName); - - return checkOrCreateChannel(manager, channelId, channelName, channelDescription, soundUri, importance, vibratePattern, showBadge); - } - - public String getNotificationDefaultChannelId() { - return this.CHANNEL_ID; - } - - private Uri getSoundUri(String soundName) { - if (soundName == null || "default".equalsIgnoreCase(soundName)) { - return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - } else { - - // sound name can be full filename, or just the resource name. - // So the strings 'my_sound.mp3' AND 'my_sound' are accepted - // The reason is to make the iOS and android javascript interfaces compatible - - int resId; - if (context.getResources().getIdentifier(soundName, "raw", context.getPackageName()) != 0) { - resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); - } else { - soundName = soundName.substring(0, soundName.lastIndexOf('.')); - resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); - } - - return Uri.parse("android.resource://" + context.getPackageName() + "/" + resId); - } - } - - public Class getMainActivityClass() { - String packageName = context.getPackageName(); - Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); - String className = launchIntent.getComponent().getClassName(); - try { - return Class.forName(className); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - return null; - } - } - - public boolean isApplicationInForeground() { - ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - List processInfos = activityManager.getRunningAppProcesses(); - if (processInfos != null) { - for (RunningAppProcessInfo processInfo : processInfos) { - if (processInfo.processName.equals(context.getPackageName()) - && processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND - && processInfo.pkgList.length > 0) { - return true; - } - } - } - return false; - } - - private Bitmap getCircleBitmap(Bitmap bitmap) { - final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), - bitmap.getHeight(), Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(output); - - final int color = Color.RED; - final Paint paint = new Paint(); - final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); - final RectF rectF = new RectF(rect); - - paint.setAntiAlias(true); - canvas.drawARGB(0, 0, 0, 0); - paint.setColor(color); - canvas.drawOval(rectF, paint); - - paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - canvas.drawBitmap(bitmap, rect, rect, paint); - - bitmap.recycle(); - - return output; - } - - private Person getPerson(Bundle bundle) { - String name = bundle.getString("name"); - - return new Person.Builder().setName(name).build(); - } - - private StatusMessage createMessage(Bundle data) { - Person author = getPerson(data.getBundle("notificationAuthor")); - long timeStampLongValue = (long) data.getDouble("timestamp"); - return new StatusMessage(data.getString("id"), author, timeStampLongValue, data.getString("message")); - } - - private PendingIntent createGroupOnDismissedIntent(Context context, int notificationId, String groupId, String deepLink) { - Intent intent = new Intent(ACTION_DELETE_NOTIFICATION); - intent.putExtra("im.status.ethereum.deepLink", deepLink); - intent.putExtra("im.status.ethereum.groupId", groupId); - return PendingIntent.getBroadcast(context.getApplicationContext(), notificationId, intent, flag); - } - - private PendingIntent createGroupOnTapIntent(Context context, int notificationId, String groupId, String deepLink) { - Intent intent = getOpenAppIntent(deepLink); - return PendingIntent.getActivity(context.getApplicationContext(), notificationId, intent, flag); - } - - private PendingIntent createOnTapIntent(Context context, int notificationId, String deepLink) { - Intent intent = getOpenAppIntent(deepLink); - return PendingIntent.getActivity(context.getApplicationContext(), notificationId, intent, flag); - } - - private PendingIntent createOnDismissedIntent(Context context, int notificationId, String deepLink) { - Intent intent = new Intent(ACTION_DELETE_NOTIFICATION); - intent.putExtra("im.status.ethereum.deepLink", deepLink); - return PendingIntent.getBroadcast(context.getApplicationContext(), notificationId, intent, flag); - } - - public void removeStatusMessage(Bundle bundle) { - String conversationId = bundle.getString("conversationId"); - StatusMessageGroup group = this.messageGroups.get(conversationId); - NotificationManager notificationManager = notificationManager(); - - if (group == null) { - group = new StatusMessageGroup(conversationId); - } - - this.messageGroups.put(conversationId, group); - - String id = bundle.getString("id"); - group.removeMessage(id); - - this.showMessages(bundle); - } - - public StatusMessageGroup getMessageGroup(String conversationId) { - return this.messageGroups.get(conversationId); - } - - public void addStatusMessage(Bundle bundle) { - String conversationId = bundle.getString("conversationId"); - StatusMessageGroup group = this.messageGroups.get(conversationId); - NotificationManager notificationManager = notificationManager(); - - if (group == null) { - group = new StatusMessageGroup(conversationId); - } - - this.messageGroups.put(conversationId, group); - - group.addMessage(createMessage(bundle)); - - this.showMessages(bundle); - } - - public void showMessages(Bundle bundle) { - String conversationId = bundle.getString("conversationId"); - StatusMessageGroup group = this.messageGroups.get(conversationId); - NotificationManager notificationManager = notificationManager(); - - NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle("Me"); - ArrayList messages = group.getMessages(); - - if (messages.size() == 0) { - notificationManager.cancel(conversationId.hashCode()); - return; - } - - for (int i = 0; i < messages.size(); i++) { - StatusMessage message = messages.get(i); - messagingStyle.addMessage(message.getText(), - message.getTimestamp(), - message.getAuthor()); - } - - if (bundle.getString("title") != null) { - messagingStyle.setConversationTitle(bundle.getString("title")); - } - - NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID) - .setSmallIcon(R.drawable.ic_stat_notify_status) - .setPriority(NotificationCompat.PRIORITY_HIGH) - .setCategory(NotificationCompat.CATEGORY_MESSAGE) - .setStyle(messagingStyle) - .setGroup(conversationId) - .setOnlyAlertOnce(true) - .setGroupSummary(true) - .setContentIntent(createGroupOnTapIntent(context, conversationId.hashCode(), conversationId, bundle.getString("deepLink"))) - .setDeleteIntent(createGroupOnDismissedIntent(context, conversationId.hashCode(), conversationId, bundle.getString("deepLink"))) - .setNumber(messages.size() + 1) - .setAutoCancel(true); - if (Build.VERSION.SDK_INT >= 21) { - builder.setVibrate(new long[0]); - } - notificationManager.notify(conversationId.hashCode(), builder.build()); - } - - class StatusMessageGroup { - private ArrayList messages; - private String id; - - StatusMessageGroup(String id) { - this.id = id; - this.messages = new ArrayList(); - } - public ArrayList getMessages() { - return messages; - } - - public void addMessage(StatusMessage message) { - this.messages.add(message); - } - - public void removeMessage(String id) { - ArrayList newMessages = new ArrayList(); - for(StatusMessage message: this.messages) { - if(!message.id.equals(id)) { - newMessages.add(message); - } - } - this.messages = newMessages; - } - - public String getId() { - return this.id; - } - } - - class StatusMessage { - public Person getAuthor() { - return author; - } - - public long getTimestamp() { - return timestamp; - } - - public String getText() { - return text; - } - - private String id; - private Person author; - private long timestamp; - private String text; - - StatusMessage(String id, Person author, long timestamp, String text) { - this.id = id; - this.author = author; - this.timestamp = timestamp; - this.text = text; - } - } - - private void removeGroup(String groupId) { - this.messageGroups.remove(groupId); - } - - private void cleanGroup(String groupId) { - removeGroup(groupId); - if (messageGroups.size() == 0) { - notificationManager.cancelAll(); - } - } - - public void start() { - Log.e(LOG_TAG, "Starting Foreground Service"); - Intent serviceIntent = new Intent(context, ForegroundService.class); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(serviceIntent); - } else { - context.startService(serviceIntent); - } - this.registerBroadcastReceiver(); - } - - public void stop() { - Log.e(LOG_TAG, "Stopping Foreground Service"); - //NOTE: we cancel all the current notifications, because the intents can't be used anymore - //since the broadcast receiver will be killed as well and won't be able to handle any intent - notificationManager.cancelAll(); - Intent serviceIntent = new Intent(context, ForegroundService.class); - context.stopService(serviceIntent); - context.unregisterReceiver(notificationActionReceiver); - } -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationHelper.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationHelper.kt new file mode 100644 index 000000000000..2869f1be9cb2 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationHelper.kt @@ -0,0 +1,750 @@ +// https://github.com/zo0r/react-native-push-notification/blob/bedc8f646aab67d594f291449fbfa24e07b64fe8/android/src/main/ +// java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java Copy-Paste with removed firebase +package im.status.ethereum.pushnotifications + +import android.app.ActivityManager +import android.app.ActivityManager.RunningAppProcessInfo +import android.app.AlarmManager +import android.app.Application +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.BroadcastReceiver +import android.content.SharedPreferences +import android.content.pm.ApplicationInfo +import android.content.res.Resources +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Color +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.PorterDuff +import android.graphics.PorterDuffXfermode +import android.graphics.Rect +import android.graphics.RectF +import android.media.AudioAttributes +import android.media.RingtoneManager +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.service.notification.StatusBarNotification +import android.util.Log +import android.util.Base64 +import androidx.annotation.RequiresApi +import androidx.core.app.NotificationCompat +import androidx.core.app.Person +import androidx.core.graphics.drawable.IconCompat +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.bridge.WritableArray +import com.facebook.react.bridge.WritableMap +import org.json.JSONArray +import org.json.JSONException +import im.status.ethereum.module.R +import im.status.ethereum.pushnotifications.PushNotification.Companion.LOG_TAG + +class PushNotificationHelper(private val context: Application, private val intentFilter: IntentFilter) { + + companion object { + private const val DEFAULT_VIBRATION: Long = 300L + private const val CHANNEL_ID = "status-im-notifications" + const val ACTION_DELETE_NOTIFICATION = "im.status.ethereum.module.DELETE_NOTIFICATION" + const val ACTION_TAP_STOP = "im.status.ethereum.module.TAP_STOP" + } + + private val flag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE + } else { + PendingIntent.FLAG_CANCEL_CURRENT + } + + private val notificationManager: NotificationManager by lazy { + context.getSystemService(NotificationManager::class.java) + } + + private val persons: MutableMap = mutableMapOf() + private val messageGroups: MutableMap = mutableMapOf() + + init { + registerBroadcastReceiver() + } + + private val notificationActionReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + when (intent.action) { + ACTION_DELETE_NOTIFICATION -> { + intent.extras?.getString("im.status.ethereum.groupId")?.let { groupId -> + cleanGroup(groupId) + } + } + ACTION_TAP_STOP -> { + stop() + System.exit(0) + } + } + Log.e(LOG_TAG, "intent received: ${intent.action}") + } + } + + private fun registerBroadcastReceiver() { + intentFilter.apply { + addAction(ACTION_DELETE_NOTIFICATION) + addAction(ACTION_TAP_STOP) + } + context.registerReceiver(notificationActionReceiver, intentFilter, Context.RECEIVER_EXPORTED) + Log.e(LOG_TAG, "Broadcast Receiver registered") + } + + fun getOpenAppIntent(deepLink: String?): Intent? { + val packageName = context.packageName + val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName) + val className = launchIntent?.component?.className ?: return null + + return try { + val intentClass = Class.forName(className) + Intent(context, intentClass).apply { + addCategory(Intent.CATEGORY_BROWSABLE) + action = Intent.ACTION_VIEW + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + deepLink?.let { data = Uri.parse(it) } + } + } catch (e: ClassNotFoundException) { + e.printStackTrace() + null + } + } + + fun invokeApp(bundle: Bundle?) { + val packageName = context.packageName + val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName) + val className = launchIntent?.component?.className ?: return + + try { + val activityClass = Class.forName(className) + Intent(context, activityClass).apply { + bundle?.let { putExtra("notification", it) } + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(this) + } + } catch (e: ClassNotFoundException) { + Log.e(LOG_TAG, "Class not found", e) + } + } + + fun getMainActivityClass(): Class<*>? { + val packageName = context.packageName + val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName) + val className = launchIntent?.component?.className ?: return null + + return try { + Class.forName(className) + } catch (e: ClassNotFoundException) { + e.printStackTrace() + null + } + } + + fun isApplicationInForeground(): Boolean { + val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + val processInfos = activityManager.runningAppProcesses ?: return false + + return processInfos.any { processInfo -> + processInfo.processName == context.packageName && + processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && + processInfo.pkgList.isNotEmpty() + } + } + + private fun getCircleBitmap(bitmap: Bitmap): Bitmap { + val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(output) + val paint = Paint().apply { + isAntiAlias = true + color = Color.RED + } + val rect = Rect(0, 0, bitmap.width, bitmap.height) + val rectF = RectF(rect) + + canvas.drawARGB(0, 0, 0, 0) + canvas.drawOval(rectF, paint) + + paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) + canvas.drawBitmap(bitmap, rect, rect, paint) + + bitmap.recycle() + return output + } + + // Represents a message in a Status conversation + data class StatusMessage( + val id: String, + val author: Person, + val timestamp: Long, + val text: String + ) + + // Represents a group of messages in a Status conversation + inner class StatusMessageGroup(val id: String) { + private val _messages = mutableListOf() + val messages: List get() = _messages.toList() + + fun addMessage(message: StatusMessage) { + _messages.add(message) + } + + fun removeMessage(id: String) { + _messages.removeAll { it.id == id } + } + } + + private fun getPerson(bundle: Bundle): Person { + return Person.Builder() + .setName(bundle.getString("name")) + .build() + } + + private fun createMessage(data: Bundle): StatusMessage { + val author = getPerson(data.getBundle("notificationAuthor") ?: Bundle()) + val timeStampLongValue = data.getDouble("timestamp").toLong() + return StatusMessage( + id = data.getString("id") ?: "", + author = author, + timestamp = timeStampLongValue, + text = data.getString("message") ?: "" + ) + } + + private fun createGroupOnDismissedIntent( + context: Context, + notificationId: Int, + groupId: String, + deepLink: String? + ): PendingIntent { + return Intent(ACTION_DELETE_NOTIFICATION).apply { + putExtra("im.status.ethereum.deepLink", deepLink) + putExtra("im.status.ethereum.groupId", groupId) + }.let { intent -> + PendingIntent.getBroadcast( + context.applicationContext, + notificationId, + intent, + flag + ) + } + } + + private fun createGroupOnTapIntent( + context: Context, + notificationId: Int, + groupId: String, + deepLink: String? + ): PendingIntent { + return getOpenAppIntent(deepLink)?.let { intent -> + PendingIntent.getActivity( + context.applicationContext, + notificationId, + intent, + flag + ) + } ?: throw IllegalStateException("Could not create open app intent") + } + + private fun createOnTapIntent( + context: Context, + notificationId: Int, + deepLink: String? + ): PendingIntent { + return getOpenAppIntent(deepLink)?.let { intent -> + PendingIntent.getActivity( + context.applicationContext, + notificationId, + intent, + flag + ) + } ?: throw IllegalStateException("Could not create open app intent") + } + + private fun createOnDismissedIntent( + context: Context, + notificationId: Int, + deepLink: String? + ): PendingIntent { + return Intent(ACTION_DELETE_NOTIFICATION).apply { + putExtra("im.status.ethereum.deepLink", deepLink) + }.let { intent -> + PendingIntent.getBroadcast( + context.applicationContext, + notificationId, + intent, + flag + ) + } + } + + fun removeStatusMessage(bundle: Bundle) { + val conversationId = bundle.getString("conversationId") ?: return + val group = messageGroups.getOrPut(conversationId) { + StatusMessageGroup(conversationId) + } + + bundle.getString("id")?.let { id -> + group.removeMessage(id) + } + + showMessages(bundle) + } + + fun getMessageGroup(conversationId: String): StatusMessageGroup? { + return messageGroups[conversationId] + } + + fun addStatusMessage(bundle: Bundle) { + val conversationId = bundle.getString("conversationId") ?: return + val group = messageGroups.getOrPut(conversationId) { + StatusMessageGroup(conversationId) + } + + group.addMessage(createMessage(bundle)) + showMessages(bundle) + } + + fun showMessages(bundle: Bundle) { + val conversationId = bundle.getString("conversationId") ?: return + val group = messageGroups[conversationId] ?: return + + val messagingStyle = NotificationCompat.MessagingStyle("Me") + + // If there are no messages, cancel the notification and return + if (group.messages.isEmpty()) { + notificationManager.cancel(conversationId.hashCode()) + return + } + + group.messages.forEach { message -> + messagingStyle.addMessage( + message.text, + message.timestamp, + message.author + ) + } + + // Set conversation title if available + bundle.getString("title")?.let { title -> + messagingStyle.conversationTitle = title + } + + val builder = NotificationCompat.Builder(context, CHANNEL_ID).apply { + setSmallIcon(R.drawable.ic_stat_notify_status) + setPriority(NotificationCompat.PRIORITY_HIGH) + setCategory(NotificationCompat.CATEGORY_MESSAGE) + setStyle(messagingStyle) + setGroup(conversationId) + setOnlyAlertOnce(true) + setGroupSummary(true) + setContentIntent(createGroupOnTapIntent(context, conversationId.hashCode(), conversationId, bundle.getString("deepLink"))) + setDeleteIntent(createGroupOnDismissedIntent(context, conversationId.hashCode(), conversationId, bundle.getString("deepLink"))) + setNumber(group.messages.size + 1) + setAutoCancel(true) + + // Set empty vibration pattern for Android 5.0 and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + setVibrate(LongArray(0)) + } + } + + // Show the notification + notificationManager.notify(conversationId.hashCode(), builder.build()) + } + + fun checkOrCreateChannel( + manager: NotificationManager?, + channelId: String, + channelName: String?, + channelDescription: String?, + soundUri: Uri?, + importance: Int, + vibratePattern: LongArray?, + showBadge: Boolean + ): Boolean { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || manager == null) { + return false + } + + val existingChannel = manager.getNotificationChannel(channelId) + val shouldCreateOrUpdate = when { + // Channel doesn't exist and we have required info + existingChannel == null && channelName != null && channelDescription != null -> true + + // Channel exists but needs update + existingChannel != null && ( + (channelName != null && existingChannel.name != channelName) || + (channelDescription != null && existingChannel.description != channelDescription) + ) -> true + + else -> false + } + + if (shouldCreateOrUpdate) { + NotificationChannel(channelId, channelName, importance).apply { + description = channelDescription + enableLights(true) + enableVibration(vibratePattern != null) + vibrationPattern = vibratePattern + setShowBadge(showBadge) + + // Configure sound + if (soundUri != null) { + val audioAttributes = AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_NOTIFICATION) + .build() + setSound(soundUri, audioAttributes) + } else { + setSound(null, null) + } + + manager.createNotificationChannel(this) + } + return true + } + + return false + } + + fun createChannel(channelInfo: ReadableMap): Boolean { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return false + } + + return checkOrCreateChannel( + manager = notificationManager, + channelId = channelInfo.getString("channelId") ?: return false, + channelName = channelInfo.getString("channelName"), + channelDescription = if (channelInfo.hasKey("channelDescription")) { + channelInfo.getString("channelDescription") + } else "", + soundUri = getSoundUri( + if (channelInfo.hasKey("soundName")) { + channelInfo.getString("soundName") + } else "default" + ), + importance = if (channelInfo.hasKey("importance")) { + channelInfo.getInt("importance") + } else 4, + vibratePattern = if (channelInfo.hasKey("vibrate") && channelInfo.getBoolean("vibrate")) { + longArrayOf(DEFAULT_VIBRATION) + } else null, + showBadge = channelInfo.hasKey("showBadge") && channelInfo.getBoolean("showBadge") + ) + } + + fun getNotificationDefaultChannelId(): String = CHANNEL_ID + + private fun getSoundUri(soundName: String?): Uri { + return when { + soundName == null || soundName.equals("default", ignoreCase = true) -> { + RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) + } + else -> { + val resources = context.resources + val packageName = context.packageName + val resId = when { + // Try to find the resource as is + resources.getIdentifier(soundName, "raw", packageName) != 0 -> { + resources.getIdentifier(soundName, "raw", packageName) + } + // Try without file extension + else -> { + val nameWithoutExtension = soundName.substringBeforeLast('.') + resources.getIdentifier(nameWithoutExtension, "raw", packageName) + } + } + Uri.parse("android.resource://$packageName/$resId") + } + } + } + +private fun removeGroup(groupId: String) { + messageGroups.remove(groupId) + } + + private fun cleanGroup(groupId: String) { + removeGroup(groupId) + if (messageGroups.isEmpty()) { + notificationManager.cancelAll() + } + } + + fun start() { + Log.e(LOG_TAG, "Starting Foreground Service") + Intent(context, ForegroundService::class.java).also { serviceIntent -> + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(serviceIntent) + } else { + context.startService(serviceIntent) + } + } + registerBroadcastReceiver() + } + + fun stop() { + Log.e(LOG_TAG, "Stopping Foreground Service") + // Cancel all current notifications since their intents won't be valid + // after the broadcast receiver is killed + notificationManager.cancelAll() + + Intent(context, ForegroundService::class.java).also { serviceIntent -> + context.stopService(serviceIntent) + } + context.unregisterReceiver(notificationActionReceiver) + } + + fun sendToNotificationCentre(bundle: Bundle) { + val aggregator = PushNotificationPicturesAggregator { largeIconImage, bigPictureImage -> + sendToNotificationCentreWithPicture(bundle, largeIconImage, bigPictureImage) + } + + aggregator.apply { + setLargeIconUrl(context, bundle.getString("largeIconUrl")) + setBigPictureUrl(context, bundle.getString("bigPictureUrl")) + } + } + + fun handleConversation(bundle: Bundle) { + if (bundle.getBoolean("deleted")) { + removeStatusMessage(bundle) + } else { + addStatusMessage(bundle) + } + } + + fun clearMessageNotifications(conversationId: String) { + notificationManager.cancel(conversationId.hashCode()) + cleanGroup(conversationId) + } + + fun clearAllMessageNotifications() { + notificationManager.cancelAll() + } + + fun sendToNotificationCentreWithPicture( + bundle: Bundle, + largeIconBitmap: Bitmap?, + bigPictureBitmap: Bitmap? + ) { + try { + val intentClass = getMainActivityClass() ?: run { + Log.e(LOG_TAG, "No activity class found for the notification") + return + } + + if (bundle.getBoolean("isConversation")) { + handleConversation(bundle) + return + } + + if (bundle.getString("message") == null) { + Log.d(LOG_TAG, "Ignore this message if you sent data-only notification. " + + "Cannot send to notification centre because there is no 'message' field in: $bundle") + return + } + + val notificationIdString = bundle.getString("id") ?: run { + Log.e(LOG_TAG, "No notification ID specified for the notification") + return + } + + val resources = context.resources + val packageName = context.packageName + + val title = bundle.getString("title") ?: run { + val appInfo = context.applicationInfo + context.packageManager.getApplicationLabel(appInfo).toString() + } + + val priority = when (bundle.getString("priority")?.toLowerCase()) { + "max" -> NotificationCompat.PRIORITY_MAX + "high" -> NotificationCompat.PRIORITY_HIGH + "low" -> NotificationCompat.PRIORITY_LOW + "min" -> NotificationCompat.PRIORITY_MIN + "default" -> NotificationCompat.PRIORITY_DEFAULT + else -> NotificationCompat.PRIORITY_HIGH + } + + val visibility = when (bundle.getString("visibility")?.toLowerCase()) { + "private" -> NotificationCompat.VISIBILITY_PRIVATE + "public" -> NotificationCompat.VISIBILITY_PUBLIC + "secret" -> NotificationCompat.VISIBILITY_SECRET + else -> NotificationCompat.VISIBILITY_PRIVATE + } + + val channelId = bundle.getString("channelId") ?: getNotificationDefaultChannelId() + + NotificationCompat.Builder(context, channelId).apply { + setContentTitle(title) + setTicker(bundle.getString("ticker")) + setVisibility(visibility) + setPriority(priority) + setAutoCancel(bundle.getBoolean("autoCancel", true)) + setOnlyAlertOnce(bundle.getBoolean("onlyAlertOnce", false)) + + // Configure notification based on Android version + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + setShowWhen(bundle.getBoolean("showWhen", true)) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setDefaults(Notification.DEFAULT_LIGHTS) + } + + // Handle group settings for Android KitKat Watch and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { + bundle.getString("group")?.let { group -> + setGroup(group) + } + + if (bundle.containsKey("groupSummary") || bundle.getBoolean("groupSummary")) { + setGroupSummary(bundle.getBoolean("groupSummary")) + } + } + + // Set notification number if provided + bundle.getString("number")?.toIntOrNull()?.let { number -> + setNumber(number) + } + + val smallIconResId = findSmallIconResourceId(resources, packageName, bundle) + setSmallIcon(smallIconResId) + + configureLargeIcon(this, largeIconBitmap, bundle, resources, packageName) + + val message = bundle.getString("message") ?: "" + setContentText(message) + + bundle.getString("subText")?.let { subText -> + setSubText(subText) + } + + val bigText = bundle.getString("bigText") ?: message + val style = when { + bigPictureBitmap != null -> NotificationCompat.BigPictureStyle() + .bigPicture(bigPictureBitmap) + .setBigContentTitle(title) + .setSummaryText(message) + else -> NotificationCompat.BigTextStyle().bigText(bigText) + } + setStyle(style) + + val notificationId = notificationIdString.hashCode() + setContentIntent(createOnTapIntent(context, notificationId, bundle.getString("deepLink"))) + setDeleteIntent(createOnDismissedIntent(context, notificationId, bundle.getString("deepLink"))) + + configureSoundAndVibration(this, bundle) + + setOngoing(bundle.getBoolean("ongoing", false)) + + // Handle color for Lollipop and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + setCategory(NotificationCompat.CATEGORY_CALL) + bundle.getString("color")?.let { color -> + setColor(Color.parseColor(color)) + } + } + + // Finally show the notification if conditions are met + if (!(isApplicationInForeground() && bundle.getBoolean("ignoreInForeground"))) { + val notification = build() + notification.defaults = notification.defaults or Notification.DEFAULT_LIGHTS + + if (bundle.containsKey("tag")) { + notificationManager.notify(bundle.getString("tag"), notificationId, notification) + } else { + notificationManager.notify(notificationId, notification) + } + } + } + + } catch (e: Exception) { + Log.e(LOG_TAG, "Failed to send push notification", e) + } + } + + private fun findSmallIconResourceId(resources: Resources, packageName: String, bundle: Bundle): Int { + val smallIcon = bundle.getString("smallIcon") + return when { + !smallIcon.isNullOrEmpty() -> + resources.getIdentifier(smallIcon, "mipmap", packageName) + smallIcon == null -> + resources.getIdentifier("ic_stat_notify_status", "drawable", packageName) + else -> { + val defaultIcon = resources.getIdentifier("ic_launcher", "mipmap", packageName) + defaultIcon.takeIf { it != 0 } ?: android.R.drawable.ic_dialog_info + } + } + } + + private fun configureLargeIcon( + builder: NotificationCompat.Builder, + largeIconBitmap: Bitmap?, + bundle: Bundle, + resources: Resources, + packageName: String + ) { + var finalLargeIcon = largeIconBitmap + + if (finalLargeIcon == null) { + val largeIcon = bundle.getString("largeIcon") + val largeIconResId = when { + !largeIcon.isNullOrEmpty() -> + resources.getIdentifier(largeIcon, "mipmap", packageName) + largeIcon == null -> + resources.getIdentifier("ic_launcher", "mipmap", packageName) + else -> 0 + } + + if (largeIconResId != 0 && (largeIcon != null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) { + finalLargeIcon = BitmapFactory.decodeResource(resources, largeIconResId) + } + } + + bundle.getBundle("notificationAuthor")?.getString("icon")?.let { icon -> + val base64Image = icon.split(",")[1] + val decodedString = Base64.decode(base64Image, Base64.DEFAULT) + val decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.size) + builder.setLargeIcon(getCircleBitmap(decodedByte)) + } ?: finalLargeIcon?.let { icon -> + builder.setLargeIcon(icon) + } + } + + private fun configureSoundAndVibration( + builder: NotificationCompat.Builder, + bundle: Bundle + ) { + var soundUri: Uri? = null + + if (!bundle.containsKey("playSound") || bundle.getBoolean("playSound")) { + val soundName = bundle.getString("soundName") ?: "default" + soundUri = getSoundUri(soundName) + builder.setSound(soundUri) + } + + if (soundUri == null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + builder.setSound(null) + } + + if (!bundle.containsKey("vibrate") || bundle.getBoolean("vibrate")) { + val vibration = if (bundle.containsKey("vibration")) { + bundle.getDouble("vibration").toLong() + } else DEFAULT_VIBRATION + + val finalVibration = if (vibration == 0L) DEFAULT_VIBRATION else vibration + builder.setVibrate(longArrayOf(0, finalVibration)) + } + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationJsDelivery.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationJsDelivery.java deleted file mode 100644 index 585dca43d542..000000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationJsDelivery.java +++ /dev/null @@ -1,86 +0,0 @@ -package im.status.ethereum.pushnotifications; - -import android.os.Build; -import android.app.Application; -import android.app.NotificationManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; - -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.modules.core.DeviceEventManagerModule; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.Set; - -import static im.status.ethereum.pushnotifications.PushNotification.LOG_TAG; - -class PushNotificationJsDelivery { - - private ReactContext reactContext; - - PushNotificationJsDelivery(ReactContext context){ - reactContext = context; - } - - String convertJSON(Bundle bundle) { - try { - JSONObject json = convertJSONObject(bundle); - return json.toString(); - } catch (JSONException e) { - return null; - } - } - - // a Bundle is not a map, so we have to convert it explicitly - private JSONObject convertJSONObject(Bundle bundle) throws JSONException { - JSONObject json = new JSONObject(); - Set keys = bundle.keySet(); - for (String key : keys) { - Object value = bundle.get(key); - if (value instanceof Bundle) { - json.put(key, convertJSONObject((Bundle)value)); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - json.put(key, JSONObject.wrap(value)); - } else { - json.put(key, value); - } - } - return json; - } - - void notifyNotification(Bundle bundle) { - String bundleString = convertJSON(bundle); - - WritableMap params = Arguments.createMap(); - params.putString("dataJSON", bundleString); - - sendEvent("remoteNotificationReceived", params); - } - - void notifyNotificationAction(Bundle bundle) { - String bundleString = convertJSON(bundle); - - WritableMap params = Arguments.createMap(); - params.putString("dataJSON", bundleString); - - sendEvent("notificationActionReceived", params); - } - - void sendEvent(String eventName, Object params) { - if (reactContext.hasActiveCatalystInstance()) { - reactContext - .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit(eventName, params); - } - } - -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationJsDelivery.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationJsDelivery.kt new file mode 100644 index 000000000000..cb22cf4c3ff9 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationJsDelivery.kt @@ -0,0 +1,93 @@ +package im.status.ethereum.pushnotifications + +import android.os.Build +import android.app.Application +import android.app.NotificationManager +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.util.Log +import com.facebook.react.bridge.ReactContext +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.modules.core.DeviceEventManagerModule +import org.json.JSONException +import org.json.JSONObject +import im.status.ethereum.pushnotifications.PushNotification.Companion.LOG_TAG + +class PushNotificationJsDelivery( + private val reactContext: ReactContext +) { + /** + * Converts a Bundle to its JSON string representation. + * Returns null if conversion fails. + */ + fun convertJSON(bundle: Bundle): String? { + return try { + convertJSONObject(bundle).toString() + } catch (e: JSONException) { + null + } + } + + /** + * Converts a Bundle to a JSONObject, handling nested bundles and different value types. + * This explicit conversion is necessary because Bundle is not a standard map. + */ + @Throws(JSONException::class) + private fun convertJSONObject(bundle: Bundle): JSONObject { + return JSONObject().apply { + // Using Kotlin's for loop syntax and 'apply' scope function + bundle.keySet().forEach { key -> + bundle.get(key)?.let { value -> + when (value) { + is Bundle -> put(key, convertJSONObject(value)) + else -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + put(key, JSONObject.wrap(value)) + } else { + put(key, value) + } + } + } + } + } + } + + /** + * Notifies about a received remote notification by sending an event to JavaScript + */ + fun notifyNotification(bundle: Bundle) { + convertJSON(bundle)?.let { bundleString -> + Arguments.createMap().apply { + putString("dataJSON", bundleString) + sendEvent("remoteNotificationReceived", this) + } + } + } + + /** + * Notifies about a notification action by sending an event to JavaScript + */ + fun notifyNotificationAction(bundle: Bundle) { + convertJSON(bundle)?.let { bundleString -> + Arguments.createMap().apply { + putString("dataJSON", bundleString) + sendEvent("notificationActionReceived", this) + } + } + } + + /** + * Sends an event to JavaScript if there's an active Catalyst instance + */ + fun sendEvent(eventName: String, params: Any) { + if (reactContext.hasActiveCatalystInstance()) { + reactContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) + .emit(eventName, params) + } + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPackage.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPackage.java deleted file mode 100644 index 0a4391fdd83e..000000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPackage.java +++ /dev/null @@ -1,27 +0,0 @@ -package im.status.ethereum.pushnotifications; - -import im.status.ethereum.pushnotifications.PushNotification; -import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JavaScriptModule; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.uimanager.ViewManager; - -import java.util.Collections; -import java.util.List; - -public class PushNotificationPackage implements ReactPackage { - @Override - public List createNativeModules(ReactApplicationContext reactContext) { - return Collections.singletonList(new PushNotification(reactContext)); - } - - public List> createJSModules() { - return Collections.emptyList(); - } - - @Override - public List createViewManagers(ReactApplicationContext reactContext) { - return Collections.emptyList(); - } -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPackage.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPackage.kt new file mode 100644 index 000000000000..cd97ca09ff19 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPackage.kt @@ -0,0 +1,24 @@ +package im.status.ethereum.pushnotifications + +import im.status.ethereum.pushnotifications.PushNotification +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.JavaScriptModule +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.uimanager.ViewManager + +class PushNotificationPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return listOf(PushNotification(reactContext)) + } + + // Note: This function is deprecated in newer versions of React Native + // but kept for backwards compatibility + fun createJSModules(): List> { + return emptyList() + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return emptyList() + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPicturesAggregator.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPicturesAggregator.java deleted file mode 100644 index f34c28cbfdba..000000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPicturesAggregator.java +++ /dev/null @@ -1,136 +0,0 @@ -package im.status.ethereum.pushnotifications; - -import androidx.annotation.Nullable; -import com.facebook.common.executors.CallerThreadExecutor; -import com.facebook.common.references.CloseableReference; -import com.facebook.datasource.DataSource; -import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.imagepipeline.common.Priority; -import com.facebook.imagepipeline.core.ImagePipeline; -import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; -import com.facebook.imagepipeline.image.CloseableImage; -import com.facebook.imagepipeline.request.ImageRequest; -import com.facebook.imagepipeline.request.ImageRequestBuilder; - -import android.util.Log; -import android.content.Context; -import android.graphics.Bitmap; -import android.net.Uri; -import java.util.concurrent.atomic.AtomicInteger; - -import static im.status.ethereum.pushnotifications.PushNotification.LOG_TAG; - -public class PushNotificationPicturesAggregator { - interface Callback { - public void call(Bitmap largeIconImage, Bitmap bigPictureImage); - } - - private AtomicInteger count = new AtomicInteger(0); - - private Bitmap largeIconImage; - private Bitmap bigPictureImage; - - private Callback callback; - - public PushNotificationPicturesAggregator(Callback callback) { - this.callback = callback; - } - - public void setBigPicture(Bitmap bitmap) { - this.bigPictureImage = bitmap; - this.finished(); - } - - public void setBigPictureUrl(Context context, String url) { - if(null == url) { - this.setBigPicture(null); - return; - } - - Uri uri = null; - - try { - uri = Uri.parse(url); - } catch(Exception ex) { - Log.e(LOG_TAG, "Failed to parse bigPictureUrl", ex); - this.setBigPicture(null); - return; - } - - final PushNotificationPicturesAggregator aggregator = this; - - this.downloadRequest(context, uri, new BaseBitmapDataSubscriber() { - @Override - public void onNewResultImpl(@Nullable Bitmap bitmap) { - aggregator.setBigPicture(bitmap); - } - - @Override - public void onFailureImpl(DataSource dataSource) { - aggregator.setBigPicture(null); - } - }); - } - - public void setLargeIcon(Bitmap bitmap) { - this.largeIconImage = bitmap; - this.finished(); - } - - public void setLargeIconUrl(Context context, String url) { - if(null == url) { - this.setLargeIcon(null); - return; - } - - Uri uri = null; - - try { - uri = Uri.parse(url); - } catch(Exception ex) { - Log.e(LOG_TAG, "Failed to parse largeIconUrl", ex); - this.setLargeIcon(null); - return; - } - - final PushNotificationPicturesAggregator aggregator = this; - - this.downloadRequest(context, uri, new BaseBitmapDataSubscriber() { - @Override - public void onNewResultImpl(@Nullable Bitmap bitmap) { - aggregator.setLargeIcon(bitmap); - } - - @Override - public void onFailureImpl(DataSource dataSource) { - aggregator.setLargeIcon(null); - } - }); - } - - private void downloadRequest(Context context, Uri uri, BaseBitmapDataSubscriber subscriber) { - ImageRequest imageRequest = ImageRequestBuilder - .newBuilderWithSource(uri) - .setRequestPriority(Priority.HIGH) - .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH) - .build(); - - if(!Fresco.hasBeenInitialized()) { - Fresco.initialize(context); - } - - DataSource> dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, context); - - dataSource.subscribe(subscriber, CallerThreadExecutor.getInstance()); - } - - private void finished() { - synchronized(this.count) { - int val = this.count.incrementAndGet(); - - if(val >= 2 && this.callback != null) { - this.callback.call(this.largeIconImage, this.bigPictureImage); - } - } - } -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPicturesAggregator.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPicturesAggregator.kt new file mode 100644 index 000000000000..f2a46b90c219 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/pushnotifications/PushNotificationPicturesAggregator.kt @@ -0,0 +1,109 @@ +package im.status.ethereum.pushnotifications + +import androidx.annotation.Nullable +import com.facebook.common.executors.CallerThreadExecutor +import com.facebook.common.references.CloseableReference +import com.facebook.datasource.DataSource +import com.facebook.drawee.backends.pipeline.Fresco +import com.facebook.imagepipeline.common.Priority +import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber +import com.facebook.imagepipeline.image.CloseableImage +import com.facebook.imagepipeline.request.ImageRequest +import com.facebook.imagepipeline.request.ImageRequestBuilder +import android.util.Log +import android.content.Context +import android.graphics.Bitmap +import android.net.Uri +import java.util.concurrent.atomic.AtomicInteger +import im.status.ethereum.pushnotifications.PushNotification.Companion.LOG_TAG + +class PushNotificationPicturesAggregator( + private val callback: (Bitmap?, Bitmap?) -> Unit +) { + private val count = AtomicInteger(0) + private var largeIconImage: Bitmap? = null + private var bigPictureImage: Bitmap? = null + + fun setBigPicture(bitmap: Bitmap?) { + bigPictureImage = bitmap + finished() + } + + fun setBigPictureUrl(context: Context, url: String?) { + if (url == null) { + setBigPicture(null) + return + } + + val uri = try { + Uri.parse(url) + } catch (ex: Exception) { + Log.e(LOG_TAG, "Failed to parse bigPictureUrl", ex) + setBigPicture(null) + return + } + + downloadRequest(context, uri, object : BaseBitmapDataSubscriber() { + override fun onNewResultImpl(@Nullable bitmap: Bitmap?) { + setBigPicture(bitmap) + } + + override fun onFailureImpl(dataSource: DataSource>) { + setBigPicture(null) + } + }) + } + + fun setLargeIcon(bitmap: Bitmap?) { + largeIconImage = bitmap + finished() + } + + fun setLargeIconUrl(context: Context, url: String?) { + if (url == null) { + setLargeIcon(null) + return + } + + val uri = try { + Uri.parse(url) + } catch (ex: Exception) { + Log.e(LOG_TAG, "Failed to parse largeIconUrl", ex) + setLargeIcon(null) + return + } + + downloadRequest(context, uri, object : BaseBitmapDataSubscriber() { + override fun onNewResultImpl(@Nullable bitmap: Bitmap?) { + setLargeIcon(bitmap) + } + + override fun onFailureImpl(dataSource: DataSource>) { + setLargeIcon(null) + } + }) + } + + private fun downloadRequest(context: Context, uri: Uri, subscriber: BaseBitmapDataSubscriber) { + val imageRequest = ImageRequestBuilder + .newBuilderWithSource(uri) + .setRequestPriority(Priority.HIGH) + .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH) + .build() + + if (!Fresco.hasBeenInitialized()) { + Fresco.initialize(context) + } + + val dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, context) + dataSource.subscribe(subscriber, CallerThreadExecutor.getInstance()) + } + + private fun finished() { + synchronized(count) { + if (count.incrementAndGet() >= 2) { + callback(largeIconImage, bigPictureImage) + } + } + } +} diff --git a/modules/react-native-status/android/src/test/java/im/status/ethereum/pushnotifications/PushNotificationHelperTest.java b/modules/react-native-status/android/src/test/java/im/status/ethereum/pushnotifications/PushNotificationHelperTest.java deleted file mode 100644 index b2e18c93e93f..000000000000 --- a/modules/react-native-status/android/src/test/java/im/status/ethereum/pushnotifications/PushNotificationHelperTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package im.status.ethereum.pushnotifications; - -import org.junit.Test; -import static org.junit.Assert.*; -import android.app.Application; -import android.app.NotificationManager; -import android.os.Bundle; - -import android.content.Intent; -import android.app.PendingIntent; -import android.content.IntentFilter; -import static org.mockito.Mockito.*; -import org.mockito.Spy; - -public class PushNotificationHelperTest { - - PushNotificationHelper helper; - - - @Test - public void testAddStatusMessage() { - final Application context = mock(Application.class); - final NotificationManager manager = mock(NotificationManager.class); - final IntentFilter filter = mock(IntentFilter.class); - - when(context.getSystemService(NotificationManager.class)).thenReturn(manager); - - // Create a spy for PushNotificationHelper - PushNotificationHelper realHelper = new PushNotificationHelper(context, filter); - helper = spy(realHelper); - - Bundle bundle = mock(Bundle.class); - Bundle personBundle = mock(Bundle.class); - - String conversationId = "conversation-id"; - String deepLink = "deep-link"; - - when(bundle.getString("conversationId")).thenReturn(conversationId); - when(bundle.getString("id")).thenReturn("id"); - when(bundle.getString("message")).thenReturn("message"); - when(bundle.getDouble("timestamp")).thenReturn(100000.0); - when(bundle.getString("deepLink")).thenReturn(deepLink); - - when(personBundle.getString("name")).thenReturn("name"); - when(bundle.getBundle("notificationAuthor")).thenReturn(personBundle); - - - doNothing().when(helper).showMessages(bundle); - - helper.addStatusMessage(bundle); - assertNotNull(helper.getMessageGroup(conversationId)); - } -} - diff --git a/modules/react-native-status/android/src/test/java/im/status/ethereum/pushnotifications/PushNotificationHelperTest.kt b/modules/react-native-status/android/src/test/java/im/status/ethereum/pushnotifications/PushNotificationHelperTest.kt new file mode 100644 index 000000000000..5477ab27955a --- /dev/null +++ b/modules/react-native-status/android/src/test/java/im/status/ethereum/pushnotifications/PushNotificationHelperTest.kt @@ -0,0 +1,49 @@ +package im.status.ethereum.pushnotifications + +import android.app.Application +import android.app.NotificationManager +import android.content.Intent +import android.content.IntentFilter +import android.os.Bundle +import org.junit.Assert.assertNotNull +import org.junit.Test +import org.mockito.Mockito.* +import org.mockito.Spy + +class PushNotificationHelperTest { + + private lateinit var helper: PushNotificationHelper + + @Test + fun testAddStatusMessage() { + val context = mock(Application::class.java) + val manager = mock(NotificationManager::class.java) + val filter = mock(IntentFilter::class.java) + + `when`(context.getSystemService(NotificationManager::class.java)).thenReturn(manager) + + // Create a spy for PushNotificationHelper + val realHelper = PushNotificationHelper(context, filter) + helper = spy(realHelper) + + val bundle = mock(Bundle::class.java) + val personBundle = mock(Bundle::class.java) + + val conversationId = "conversation-id" + val deepLink = "deep-link" + + `when`(bundle.getString("conversationId")).thenReturn(conversationId) + `when`(bundle.getString("id")).thenReturn("id") + `when`(bundle.getString("message")).thenReturn("message") + `when`(bundle.getDouble("timestamp")).thenReturn(100000.0) + `when`(bundle.getString("deepLink")).thenReturn(deepLink) + + `when`(personBundle.getString("name")).thenReturn("name") + `when`(bundle.getBundle("notificationAuthor")).thenReturn(personBundle) + + doNothing().`when`(helper).showMessages(bundle) + + helper.addStatusMessage(bundle) + assertNotNull(helper.getMessageGroup(conversationId)) + } +} From ba8cf8e8639edfce8f517b8fa128b9475fa8b76f Mon Sep 17 00:00:00 2001 From: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com> Date: Tue, 7 Jan 2025 19:04:01 +0530 Subject: [PATCH 04/15] fix(wallet)_: collectible route cleanup on navigating back from TX confirmation page (#21883) This commit fixes routes not cleaned properly ("Context Canceled" and "No Routes Found" errors thrown on generating the next route) when the user navigates back from the TX confirmation screen using the device's back button/gesture. Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com> --- .../contexts/wallet/collectible/utils.cljs | 11 +- .../contexts/wallet/send/events.cljs | 27 +- .../send/transaction_confirmation/view.cljs | 245 +++++++++--------- 3 files changed, 141 insertions(+), 142 deletions(-) diff --git a/src/status_im/contexts/wallet/collectible/utils.cljs b/src/status_im/contexts/wallet/collectible/utils.cljs index f6d2bcb411a0..3c4a6cc5f76a 100644 --- a/src/status_im/contexts/wallet/collectible/utils.cljs +++ b/src/status_im/contexts/wallet/collectible/utils.cljs @@ -2,14 +2,15 @@ (:require [status-im.config :as config] [status-im.constants :as constants] [status-im.contexts.wallet.common.utils.networks :as network-utils] - [taoensso.timbre :as log])) + [taoensso.timbre :as log] + [utils.number :as utils.number])) (defn collectible-balance ([{:keys [ownership]} address] - (let [balance (some #(when (= address (:address %)) - (js/parseInt (:balance %))) - ownership)] - (if (js/Number.isNaN balance) 0 balance)))) + (->> ownership + (some #(when (= address (:address %)) + (:balance %))) + utils.number/parse-int))) (def supported-collectible-types #{"image/jpeg" diff --git a/src/status_im/contexts/wallet/send/events.cljs b/src/status_im/contexts/wallet/send/events.cljs index 7f874f9c01b6..bc6a4ea31cb8 100644 --- a/src/status_im/contexts/wallet/send/events.cljs +++ b/src/status_im/contexts/wallet/send/events.cljs @@ -742,22 +742,19 @@ (assoc params :network network)]))}])}]]])}))) (rf/reg-event-fx - :wallet/transaction-confirmation-navigate-back + :wallet/clean-route-data-for-collectible-tx (fn [{db :db}] - (let [tx-type (-> db :wallet :ui :send :tx-type) - keep-tx-data? (#{:account-collectible-tab :wallet-stack} - (-> db :wallet :ui :send :entry-point)) - delete-data-for-erc-721-tx? (and (= tx-type :tx/collectible-erc-721) (not keep-tx-data?)) - erc-1155-tx? (= tx-type :tx/collectible-erc-1155)] - {:db (cond-> db - delete-data-for-erc-721-tx? - (update-in [:wallet :ui :send] dissoc :tx-type :amount :route :suggested-routes) - - erc-1155-tx? - (update-in [:wallet :ui :send] dissoc :route :suggested-routes)) - :fx [(when (or delete-data-for-erc-721-tx? erc-1155-tx?) - [:dispatch [:wallet/stop-and-clean-suggested-routes]]) - [:dispatch [:navigate-back]]]}))) + (when (send-utils/tx-type-collectible? (-> db :wallet :ui :send :tx-type)) + {:db (update-in db + [:wallet :ui :send] + dissoc + :amount + :route + :suggested-routes + :last-request-uuid + :transaction-for-signing + :sign-transactions-callback-fx) + :fx [[:dispatch [:wallet/stop-and-clean-suggested-routes]]]}))) (rf/reg-event-fx :wallet/collectible-amount-navigate-back diff --git a/src/status_im/contexts/wallet/send/transaction_confirmation/view.cljs b/src/status_im/contexts/wallet/send/transaction_confirmation/view.cljs index 640122509162..3535e680954a 100644 --- a/src/status_im/contexts/wallet/send/transaction_confirmation/view.cljs +++ b/src/status_im/contexts/wallet/send/transaction_confirmation/view.cljs @@ -5,6 +5,7 @@ [quo.theme :as quo.theme] [react-native.core :as rn] [react-native.safe-area :as safe-area] + [status-im.common.events-helper :as events-helper] [status-im.common.floating-button-page.view :as floating-button-page] [status-im.common.standard-authentication.core :as standard-auth] [status-im.contexts.wallet.common.utils :as utils] @@ -12,6 +13,7 @@ [status-im.contexts.wallet.send.transaction-settings.view :as transaction-settings] [status-im.contexts.wallet.send.utils :as send-utils] [status-im.feature-flags :as ff] + [status-im.setup.hot-reload :as hot-reload] [utils.i18n :as i18n] [utils.re-frame :as rf])) @@ -210,125 +212,124 @@ (defn view [_] - (let [on-close #(rf/dispatch [:wallet/transaction-confirmation-navigate-back])] - (fn [] - (let [theme (quo.theme/use-theme) - send-transaction-data (rf/sub [:wallet/wallet-send]) - {:keys [token-display-name collectible amount - route - to-address bridge-to-chain-id type - recipient]} send-transaction-data - collectible? (some? collectible) - image-url (when collectible - (get-in collectible [:preview-url :uri])) - transaction-type (:tx-type send-transaction-data) - estimated-time-min (reduce + (map :estimated-time route)) - token-symbol (or token-display-name - (-> send-transaction-data :token :symbol)) - first-route (first route) - native-currency-symbol (get-in first-route - [:from :native-currency-symbol]) - fee-formatted (rf/sub [:wallet/wallet-send-fee-fiat-formatted - native-currency-symbol]) - account (rf/sub [:wallet/current-viewing-account]) - account-color (:color account) - bridge-to-network (when bridge-to-chain-id - (rf/sub [:wallet/network-details-by-chain-id - bridge-to-chain-id])) - loading-suggested-routes? (rf/sub - [:wallet/wallet-send-loading-suggested-routes?]) - transaction-for-signing (rf/sub [:wallet/wallet-send-transaction-for-signing]) - from-account-props {:customization-color account-color - :size 32 - :emoji (:emoji account) - :type :default - :name (:name account) - :address (utils/get-shortened-address - (:address - account))} - user-props {:full-name to-address - :address (utils/get-shortened-address - to-address)} - sign-on-keycard? (get-in transaction-for-signing - [:signingDetails :signOnKeycard])] - ;; In token send flow we already have transaction built when - ;; we reach confirmation screen. But in send collectible flow - ;; routes request happens at the same time with navigation to - ;; confirmation screen. So we need to build the transaction as soon - ;; as route is available. - (rn/use-effect - (fn [] - (when (and (send-utils/tx-type-collectible? transaction-type) - first-route) - (rf/dispatch [:wallet/build-transaction-for-collectible-route]))) - [first-route]) - [rn/view {:style {:flex 1}} - [floating-button-page/view - {:footer-container-padding 0 - :header [quo/page-nav - {:icon-name :i/arrow-left - :on-press on-close - :margin-top (safe-area/get-top) - :background :blur - :accessibility-label :top-bar}] - :footer [:<> - [transaction-details - {:estimated-time-min estimated-time-min - :max-fees fee-formatted - :to-network bridge-to-network - :theme theme - :route route - :transaction-type transaction-type}] - (when (and (not loading-suggested-routes?) route (seq route)) - [standard-auth/slide-button - {:size :size-48 - :track-text (if (= transaction-type :tx/bridge) - (i18n/label :t/slide-to-bridge) - (i18n/label :t/slide-to-send)) - :container-style {:z-index 2} - :disabled? (not transaction-for-signing) - :customization-color account-color - :auth-button-label (i18n/label :t/confirm) - :on-complete (when sign-on-keycard? - #(rf/dispatch - [:wallet/prepare-signatures-for-transactions - :send - ""])) - :on-auth-success - (fn [psw] - (rf/dispatch - [:wallet/prepare-signatures-for-transactions :send - psw]))}])] - :gradient-cover? true - :customization-color (:color account)} - [rn/view - [transaction-title - {:token-display-name token-symbol - :amount amount - :account account - :type type - :recipient recipient - :route route - :to-network bridge-to-network - :image-url image-url - :transaction-type transaction-type - :collectible? collectible?}] - [user-summary - {:summary-type :status-account - :accessibility-label :summary-from-label - :label (i18n/label :t/from-capitalized) - :account-props from-account-props - :theme theme}] - [user-summary - {:summary-type (if (= transaction-type :tx/bridge) - :status-account - :account) - :accessibility-label :summary-to-label - :label (i18n/label :t/to-capitalized) - :account-props (if (= transaction-type :tx/bridge) - from-account-props - user-props) - :recipient recipient - :bridge-tx? (= transaction-type :tx/bridge) - :account-to? true - :theme theme}]]]])))) + (let [theme (quo.theme/use-theme) + send-transaction-data (rf/sub [:wallet/wallet-send]) + {:keys [token-display-name collectible amount + route + to-address bridge-to-chain-id type + recipient]} send-transaction-data + collectible? (some? collectible) + image-url (when collectible + (get-in collectible [:preview-url :uri])) + transaction-type (:tx-type send-transaction-data) + estimated-time-min (reduce + (map :estimated-time route)) + token-symbol (or token-display-name + (-> send-transaction-data :token :symbol)) + first-route (first route) + native-currency-symbol (get-in first-route + [:from :native-currency-symbol]) + fee-formatted (rf/sub [:wallet/wallet-send-fee-fiat-formatted + native-currency-symbol]) + account (rf/sub [:wallet/current-viewing-account]) + account-color (:color account) + bridge-to-network (when bridge-to-chain-id + (rf/sub [:wallet/network-details-by-chain-id + bridge-to-chain-id])) + loading-suggested-routes? (rf/sub + [:wallet/wallet-send-loading-suggested-routes?]) + transaction-for-signing (rf/sub [:wallet/wallet-send-transaction-for-signing]) + from-account-props {:customization-color account-color + :size 32 + :emoji (:emoji account) + :type :default + :name (:name account) + :address (utils/get-shortened-address + (:address + account))} + user-props {:full-name to-address + :address (utils/get-shortened-address + to-address)} + sign-on-keycard? (get-in transaction-for-signing + [:signingDetails :signOnKeycard])] + (hot-reload/use-safe-unmount #(rf/dispatch [:wallet/clean-route-data-for-collectible-tx])) + ;; In token send flow we already have transaction built when + ;; we reach confirmation screen. But in send collectible flow + ;; routes request happens at the same time with navigation to + ;; confirmation screen. So we need to build the transaction as soon + ;; as route is available. + (rn/use-effect + (fn [] + (when (and (send-utils/tx-type-collectible? transaction-type) + first-route) + (rf/dispatch [:wallet/build-transaction-for-collectible-route]))) + [first-route]) + [rn/view {:style {:flex 1}} + [floating-button-page/view + {:footer-container-padding 0 + :header [quo/page-nav + {:icon-name :i/arrow-left + :on-press events-helper/navigate-back + :margin-top (safe-area/get-top) + :background :blur + :accessibility-label :top-bar}] + :footer [:<> + [transaction-details + {:estimated-time-min estimated-time-min + :max-fees fee-formatted + :to-network bridge-to-network + :theme theme + :route route + :transaction-type transaction-type}] + (when (and (not loading-suggested-routes?) route (seq route)) + [standard-auth/slide-button + {:size :size-48 + :track-text (if (= transaction-type :tx/bridge) + (i18n/label :t/slide-to-bridge) + (i18n/label :t/slide-to-send)) + :container-style {:z-index 2} + :disabled? (not transaction-for-signing) + :customization-color account-color + :auth-button-label (i18n/label :t/confirm) + :on-complete (when sign-on-keycard? + #(rf/dispatch + [:wallet/prepare-signatures-for-transactions + :send + ""])) + :on-auth-success + (fn [psw] + (rf/dispatch + [:wallet/prepare-signatures-for-transactions :send + psw]))}])] + :gradient-cover? true + :customization-color (:color account)} + [rn/view + [transaction-title + {:token-display-name token-symbol + :amount amount + :account account + :type type + :recipient recipient + :route route + :to-network bridge-to-network + :image-url image-url + :transaction-type transaction-type + :collectible? collectible?}] + [user-summary + {:summary-type :status-account + :accessibility-label :summary-from-label + :label (i18n/label :t/from-capitalized) + :account-props from-account-props + :theme theme}] + [user-summary + {:summary-type (if (= transaction-type :tx/bridge) + :status-account + :account) + :accessibility-label :summary-to-label + :label (i18n/label :t/to-capitalized) + :account-props (if (= transaction-type :tx/bridge) + from-account-props + user-props) + :recipient recipient + :bridge-tx? (= transaction-type :tx/bridge) + :account-to? true + :theme theme}]]]])) From 3697f63ab0f5bd5a7ca43eb0da8c2bb8f35dc549 Mon Sep 17 00:00:00 2001 From: Parvesh Monu Date: Wed, 8 Jan 2025 11:22:19 +0530 Subject: [PATCH 05/15] Fix syncing flow navigation and designs (#21884) --- .../contexts/onboarding/intro/view.cljs | 1 - .../onboarding/syncing/progress/style.cljs | 3 +- .../onboarding/syncing/progress/view.cljs | 29 ++++++++++--------- .../contexts/profile/login/events.cljs | 2 +- translations/en.json | 7 +++-- translations/ja.json | 1 - 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/status_im/contexts/onboarding/intro/view.cljs b/src/status_im/contexts/onboarding/intro/view.cljs index 34d2371fd92d..4966072033dc 100644 --- a/src/status_im/contexts/onboarding/intro/view.cljs +++ b/src/status_im/contexts/onboarding/intro/view.cljs @@ -73,7 +73,6 @@ [quo/bottom-actions (cond-> {:container-style (style/bottom-actions-container (safe-area/get-bottom)) - :actions :two-vertical-actions :description :bottom :description-text [terms]} diff --git a/src/status_im/contexts/onboarding/syncing/progress/style.cljs b/src/status_im/contexts/onboarding/syncing/progress/style.cljs index f5da77a634b8..37f4c1785978 100644 --- a/src/status_im/contexts/onboarding/syncing/progress/style.cljs +++ b/src/status_im/contexts/onboarding/syncing/progress/style.cljs @@ -21,9 +21,10 @@ :background-color (when-not in-onboarding? colors/neutral-80-opa-80-blur)}) (defn page-illustration - [width] + [width pairing-progress?] {:flex 1 :width width :align-items :center + :margin-vertical (when pairing-progress? 24) :align-self :center :justify-content :center}) diff --git a/src/status_im/contexts/onboarding/syncing/progress/view.cljs b/src/status_im/contexts/onboarding/syncing/progress/view.cljs index ad5766ec108a..dc4916929d0e 100644 --- a/src/status_im/contexts/onboarding/syncing/progress/view.cljs +++ b/src/status_im/contexts/onboarding/syncing/progress/view.cljs @@ -18,11 +18,10 @@ [quo/text-combinations {:container-style {:margin-top 56 :margin-horizontal 20} :title (i18n/label (if pairing-progress? - :t/sync-devices-title + :t/sync-profile-title :t/sync-devices-error-title)) - :description (i18n/label (if pairing-progress? - :t/sync-devices-sub-title - :t/sync-devices-error-sub-title)) + :description (when-not pairing-progress? + (i18n/label :t/sync-devices-error-sub-title)) :title-accessibility-label :progress-screen-title :description-accessibility-label :progress-screen-sub-title}]) @@ -43,22 +42,21 @@ (defn try-again-button [profile-color logged-in?] [quo/bottom-actions - {:actions (if logged-in? :one-action :two-actions) + {:actions (if logged-in? :one-action :two-vertical-actions) :blur? true - :button-one-label (i18n/label :t/recovery-phrase) - :button-one-props {:type :primary + :container-style {:height (when-not logged-in? 116)} + :button-two-label (i18n/label :t/use-recovery-phrase) + :button-two-props {:type :primary :accessibility-label :try-seed-phrase-button :customization-color profile-color - :container-style {:flex 1} :size 40 :on-press navigate-to-enter-seed-phrase} - (if logged-in? :button-one-label :button-two-label) + :button-one-label (i18n/label :t/try-again) - (if logged-in? :button-one-props :button-two-props) + :button-one-props {:type (if logged-in? :primary :grey) :accessibility-label :try-again-later-button :customization-color profile-color - :container-style {:flex 1} :size 40 :on-press #(try-again logged-in?)}}]) @@ -66,7 +64,7 @@ [pairing-progress?] [rn/image {:resize-mode :contain - :style (style/page-illustration (:width (rn/get-window))) + :style (style/page-illustration (:width (rn/get-window)) pairing-progress?) :source (resources/get-image (if pairing-progress? :syncing-devices :syncing-wrong))}]) (defn view @@ -83,7 +81,12 @@ [quo/page-nav {:type :no-title :background :blur}] [page-title pairing-progress?] [illustration pairing-progress?] - (when-not (pairing-progress pairing-status) + (if pairing-progress? + [quo/information-box + {:type :default + :blur? true + :style {:margin-vertical 11 :margin-horizontal 12}} + (i18n/label :t/sync-devices-sub-title)] [try-again-button profile-color logged-in?])])) (defn view-onboarding diff --git a/src/status_im/contexts/profile/login/events.cljs b/src/status_im/contexts/profile/login/events.cljs index c29f2ec5af91..189c77deb942 100644 --- a/src/status_im/contexts/profile/login/events.cljs +++ b/src/status_im/contexts/profile/login/events.cljs @@ -82,7 +82,7 @@ [:dispatch [:centralized-metrics/track :metric/keycard-login]])] (cond pairing-completed? - [[:dispatch [:update-theme-and-init-root :screen/onboarding.syncing-results]]] + [[:dispatch [:onboarding/finish-onboarding false]]] (get db :onboarding/new-account?) [[:dispatch [:onboarding/finalize-setup]] diff --git a/translations/en.json b/translations/en.json index 3b44da717f41..24c216a6c0a6 100644 --- a/translations/en.json +++ b/translations/en.json @@ -2517,14 +2517,15 @@ "sync-code-generated": "Sync code generated", "sync-devices-complete-sub-title": "Your devices are now in sync", "sync-devices-complete-title": "Device sync complete!", - "sync-devices-error-sub-title": "Make sure both devices are powered on and connected to the internet.", - "sync-devices-error-title": "Oops, something’s wrong", + "sync-devices-error-sub-title": "Try again and double-check the instructions", + "sync-devices-error-title": "Oops, something’s wrong!", "sync-devices-result-sub-title": "Your devices are now in sync", - "sync-devices-sub-title": "Please keep both devices switched on and connected to the internet until sync is complete", + "sync-devices-sub-title": "Please keep both devices switched on and connected to the same network until sync is complete.", "sync-devices-title": "Syncing devices...", "sync-in-progress": "Syncing...", "sync-new-device": "Sync new device", "sync-or-recover-profile": "Sync or recover profile", + "sync-profile-title": "Syncing profile...", "sync-settings": "Sync settings", "sync-synced": "In sync", "sync-your-profile": "Sync your profile", diff --git a/translations/ja.json b/translations/ja.json index c7728bc23d46..1388e134731a 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -1913,7 +1913,6 @@ "sync-code-generated": "同期コードが生成されました", "sync-devices-complete-sub-title": "お使いのデバイスが同期されました", "sync-devices-complete-title": "デバイスの同期が完了しました!", - "sync-devices-error-sub-title": "両方のデバイスの電源がオンになっていて、インターネットに接続されていることを確認してください。", "sync-devices-error-title": "おっと、何かが間違っています", "sync-devices-result-sub-title": "お使いのデバイスが同期されました", "sync-devices-sub-title": "同期が完了するまで、両方のデバイスの電源を入れ、インターネットに接続したままにしてください。", From fad5119ceb4cdd1dde64134fe8259dd5ae70899a Mon Sep 17 00:00:00 2001 From: flexsurfer Date: Wed, 8 Jan 2025 11:47:53 +0100 Subject: [PATCH 06/15] [#21825] [Android] Java error at the and of faild Migration to a Keycard flow (#21889) --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 34613854cf39..2f050823e92c 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "react-native-shake": "^3.3.1", "react-native-share": "10.0.2", "react-native-static-safe-area-insets": "^2.2.0", - "react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.4", + "react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.5", "react-native-svg": "13.10.0", "react-native-webview": "13.6.3", "react-syntax-highlighter": "^15.5.0" diff --git a/yarn.lock b/yarn.lock index 84ae3615c1e3..1e6c9d92dd2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9479,9 +9479,9 @@ react-native-static-safe-area-insets@^2.2.0: resolved "https://registry.yarnpkg.com/react-native-static-safe-area-insets/-/react-native-static-safe-area-insets-2.2.0.tgz#dd86b6a38f43964fac8df8c0e6bc8e062527786c" integrity sha512-TLTW2e2kRK3COSK8gMZzwp4wHguFCtcO18itDLn5av/xQblXt9ylu84o+qD9aKJCBfvtNzGOvqqTKqC5GJRZ/g== -"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.4": +"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.5": version "2.6.2" - resolved "git+https://github.com/status-im/react-native-status-keycard.git#e78f46de10d65cfef2df2f62b6f41e64e0c332b9" + resolved "git+https://github.com/status-im/react-native-status-keycard.git#5b456ea3654d1344d9ae26fe88a2051719394dfe" react-native-svg@13.10.0: version "13.10.0" From b88bbda3c585918126a19f7e0b87e2cb07edbd48 Mon Sep 17 00:00:00 2001 From: Volodymyr Kozieiev Date: Wed, 8 Jan 2025 11:32:44 +0000 Subject: [PATCH 07/15] Reverted some code after cleanup (#21892) --- src/legacy/status_im/events.cljs | 1 + src/status_im/subs/profile.cljs | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/legacy/status_im/events.cljs b/src/legacy/status_im/events.cljs index d8a6046ad912..12cde36a03b4 100644 --- a/src/legacy/status_im/events.cljs +++ b/src/legacy/status_im/events.cljs @@ -7,6 +7,7 @@ legacy.status-im.chat.models.loading legacy.status-im.data-store.chats legacy.status-im.data-store.visibility-status-updates + legacy.status-im.ens.core legacy.status-im.fleet.core legacy.status-im.group-chats.core legacy.status-im.log-level.core diff --git a/src/status_im/subs/profile.cljs b/src/status_im/subs/profile.cljs index 81fac798f0ec..e9f424432abb 100644 --- a/src/status_im/subs/profile.cljs +++ b/src/status_im/subs/profile.cljs @@ -100,12 +100,24 @@ (fn [{:keys [public-key]}] public-key)) +(re-frame/reg-sub + :profile/light-client-enabled? + :<- [:profile/profile] + (fn [profile] + (get-in profile [:wakuv2-config :LightClient]))) + (re-frame/reg-sub :profile/store-confirmations-enabled? :<- [:profile/profile] (fn [profile] (get-in profile [:wakuv2-config :EnableStoreConfirmationForMessagesSent]))) +(re-frame/reg-sub + :profile/peer-syncing-enabled? + :<- [:profile/profile] + (fn [profile] + (:peer-syncing-enabled? profile))) + (re-frame/reg-sub :profile/telemetry-enabled? :<- [:profile/profile] From 32a3f856945b7c92b2aa95cb3a867d572b100d1d Mon Sep 17 00:00:00 2001 From: Ulises Manuel <90291778+ulisesmac@users.noreply.github.com> Date: Wed, 8 Jan 2025 18:16:19 -0600 Subject: [PATCH 08/15] fix(avatars) - Blinking all over the app and improvement in UX (#21782) * Change multiple uses of `merge` to `assoc` in flat-list wrapper * Fix fast-image wrapper to avoid blinking * merge -> assoc usage in chat-item component * Fix avatar not being updated when the user changes their username * Fix scalable avatar issues - On Android, the border was inconsistent depending on the theme. - Fix animation, simplify the calculation, and now it matches designs * Avoid blinking by using rn/memo --- src/react_native/fast_image.cljs | 101 ++++++++++++------ src/react_native/flat_list.cljs | 25 +++-- .../common/scalable_avatar/style.cljs | 15 ++- .../common/scalable_avatar/view.cljs | 32 ++---- .../forgot_password_doc/view.cljs | 15 +-- .../chat/home/chat_list_item/view.cljs | 3 +- src/status_im/contexts/chat/home/view.cljs | 11 +- .../profile/settings/header/header_shape.cljs | 6 +- .../profile/settings/header/style.cljs | 16 ++- .../profile/settings/header/view.cljs | 62 +++++------ .../contexts/profile/settings/view.cljs | 2 +- 11 files changed, 150 insertions(+), 138 deletions(-) diff --git a/src/react_native/fast_image.cljs b/src/react_native/fast_image.cljs index 0f5b0a4fc29c..e8481a2b2187 100644 --- a/src/react_native/fast_image.cljs +++ b/src/react_native/fast_image.cljs @@ -1,40 +1,79 @@ (ns react-native.fast-image (:require ["react-native-fast-image" :as FastImage] + [clojure.string :as string] [react-native.core :as rn] - [reagent.core :as reagent])) + [reagent.core :as reagent] + [utils.transforms :as transforms])) -(def fast-image-class (reagent/adapt-react-class ^js FastImage)) +(defn- build-source + [source] + (if (string? source) + {:uri source + :priority :high} + source)) -(defn placeholder - [style child] - [rn/view {:style (merge style {:flex 1 :justify-content :center :align-items :center})} - child]) +(defn- remove-port + [source] + (cond + (string? source) (string/replace-first source #":\d+" "") + (:uri source) (some-> source + :uri + (string/replace-first #":\d+" "")) + :else source)) -(defn fast-image +(defn- placeholder + [{:keys [style fallback-content error? loaded?]}] + [rn/view + {:style (assoc style + :flex 1 + :justify-content :center + :align-items :center)} + (cond + (and error? fallback-content) fallback-content + error? [rn/text "X"] + (not loaded?) [rn/activity-indicator {:animating true}])]) + +;; We cannot use hooks since `reactify-component` seems to ignore the functional compiler +(defn- internal-fast-image [_] - (let [loaded? (reagent/atom false) - error? (reagent/atom false)] - (fn [{:keys [source fallback-content] :as props}] - [fast-image-class - (merge - props - {:source (if (string? source) - {:uri source - :priority :high} - source) - :on-error (fn [e] - (when-let [on-error (:on-error props)] - (on-error e)) - (reset! error? true)) - :on-load (fn [e] - (when-let [on-load (:on-load props)] - (on-load e)) - (reset! loaded? true) - (reset! error? false))}) + (let [loaded? (reagent/atom false) + error? (reagent/atom false) + on-image-error (fn [event on-error] + (when (fn? on-error) (on-error event)) + (reset! error? true)) + on-image-loaded (fn [event on-load] + (when (fn? on-load) (on-load event)) + (reset! loaded? true) + (reset! error? false))] + (fn [{:keys [source fallback-content on-error on-load] :as props}] + [:> FastImage + (assoc props + :source (build-source source) + :on-error #(on-image-error % on-error) + :on-load #(on-image-loaded % on-load)) (when (or @error? (not @loaded?)) - [placeholder (:style props) - (if @error? - (or fallback-content [rn/text "X"]) - (when-not @loaded? - [rn/activity-indicator {:animating true}]))])]))) + [placeholder + {:style (js->clj (:style props)) + :fallback-content fallback-content + :error? @error? + :loaded? @loaded?}])]))) + +(defn- compare-props + [old-props new-props] + (let [old-props-clj (transforms/js->clj old-props) + new-props-clj (transforms/js->clj new-props) + old-source (some-> old-props-clj + :source + remove-port) + new-source (some-> new-props-clj + :source + remove-port)] + (and (= old-source new-source) + (= (dissoc old-props-clj :source) (dissoc new-props-clj :source))))) + +(def fast-image + (-> internal-fast-image + (reagent/reactify-component) + (rn/memo compare-props) + (reagent/adapt-react-class))) diff --git a/src/react_native/flat_list.cljs b/src/react_native/flat_list.cljs index 33047d897abe..91bbc1bba857 100644 --- a/src/react_native/flat_list.cljs +++ b/src/react_native/flat_list.cljs @@ -23,19 +23,22 @@ (when f (f data index)))) +(defn dissoc-custom-props + [props] + (dissoc props :data :header :footer :empty-component :separator :render-fn :key-fn :on-drag-end-fn)) + (defn base-list-props - [{:keys [key-fn render-fn empty-component header footer separator data render-data on-drag-end-fn] + [{:keys [key-fn data render-fn empty-component header footer separator render-data on-drag-end-fn] :as props}] - (merge - {:data (to-array data)} - (when key-fn {:keyExtractor (wrap-key-fn key-fn)}) - (when render-fn {:renderItem (wrap-render-fn render-fn render-data)}) - (when separator {:ItemSeparatorComponent (fn [] (reagent/as-element separator))}) - (when empty-component {:ListEmptyComponent (fn [] (reagent/as-element empty-component))}) - (when header {:ListHeaderComponent (reagent/as-element header)}) - (when footer {:ListFooterComponent (reagent/as-element footer)}) - (when on-drag-end-fn {:onDragEnd (wrap-on-drag-end-fn on-drag-end-fn)}) - (dissoc props :data :header :footer :empty-component :separator :render-fn :key-fn :on-drag-end-fn))) + (cond-> {:data (to-array data)} + key-fn (assoc :keyExtractor (wrap-key-fn key-fn)) + render-fn (assoc :renderItem (wrap-render-fn render-fn render-data)) + separator (assoc :ItemSeparatorComponent (fn [] (reagent/as-element separator))) + empty-component (assoc :ListEmptyComponent (fn [] (reagent/as-element empty-component))) + header (assoc :ListHeaderComponent (reagent/as-element header)) + footer (assoc :ListFooterComponent (reagent/as-element footer)) + on-drag-end-fn (assoc :onDragEnd (wrap-on-drag-end-fn on-drag-end-fn)) + :always (merge (dissoc-custom-props props)))) (defn flat-list [props] diff --git a/src/status_im/common/scalable_avatar/style.cljs b/src/status_im/common/scalable_avatar/style.cljs index 60a289994f8d..ed8404145fcf 100644 --- a/src/status_im/common/scalable_avatar/style.cljs +++ b/src/status_im/common/scalable_avatar/style.cljs @@ -1,11 +1,10 @@ (ns status-im.common.scalable-avatar.style) (defn wrapper - [{:keys [scale margin-top margin border-color]}] - [{:transform [{:scale scale}] - :margin-top margin-top - :margin-left margin - :margin-bottom margin} - {:border-width 4 - :border-color border-color - :border-radius 100}]) + [border-color scale] + [{:transform-origin "bottom left" + :border-width 4 + :border-color border-color + :border-radius 100 + :transform [{:scale 1} {:translate-y 4}]} + {:transform [{:scale scale} {:translate-y 4}]}]) diff --git a/src/status_im/common/scalable_avatar/view.cljs b/src/status_im/common/scalable_avatar/view.cljs index 3bdee91abf60..6b8052e9b041 100644 --- a/src/status_im/common/scalable_avatar/view.cljs +++ b/src/status_im/common/scalable_avatar/view.cljs @@ -2,30 +2,14 @@ (:require [quo.core :as quo] [react-native.reanimated :as reanimated] [status-im.common.scalable-avatar.style :as style])) -(def scroll-animation-input-range [0 50]) -(def header-extrapolation-option - {:extrapolateLeft "clamp" - :extrapolateRight "clamp"}) -(defn f-avatar +(def scroll-range #js [0 48]) +(def scale-range #js [1 0.4]) + +(defn view [{:keys [scroll-y full-name online? profile-picture customization-color border-color]}] - (let [image-scale-animation (reanimated/interpolate scroll-y - scroll-animation-input-range - [1 0.4] - header-extrapolation-option) - image-top-margin-animation (reanimated/interpolate scroll-y - scroll-animation-input-range - [0 20] - header-extrapolation-option) - image-side-margin-animation (reanimated/interpolate scroll-y - scroll-animation-input-range - [-4 -20] - header-extrapolation-option)] - [reanimated/view - {:style (style/wrapper {:scale image-scale-animation - :margin-top image-top-margin-animation - :margin image-side-margin-animation - :border-color border-color})} + (let [image-scale (reanimated/interpolate scroll-y scroll-range scale-range :clamp)] + [reanimated/view {:style (style/wrapper border-color image-scale)} [quo/user-avatar {:full-name full-name :online? online? @@ -34,7 +18,3 @@ :ring? true :customization-color customization-color :size :big}]])) - -(defn view - [props] - [:f> f-avatar props]) diff --git a/src/status_im/common/standard_authentication/forgot_password_doc/view.cljs b/src/status_im/common/standard_authentication/forgot_password_doc/view.cljs index 938c4686a033..4dfe9a7e3316 100644 --- a/src/status_im/common/standard_authentication/forgot_password_doc/view.cljs +++ b/src/status_im/common/standard_authentication/forgot_password_doc/view.cljs @@ -10,14 +10,12 @@ [quo/documentation-drawers {:title (i18n/label :t/forgot-your-password-info-title) :shell? shell?} - [rn/view - {:style style/container} + [rn/view {:style style/container} [quo/text {:size :paragraph-2} (i18n/label :t/forgot-your-password-info-description)] [rn/view {:style style/step-container} [quo/step {:in-blur-view? shell?} 1] - [rn/view - {:style style/step-content} + [rn/view {:style style/step-content} [quo/text {:size :paragraph-2 :weight :semi-bold} (i18n/label :t/forgot-your-password-info-remove-app)] [quo/text {:size :paragraph-2} (i18n/label :t/forgot-your-password-info-remove-app-description)]]] @@ -33,10 +31,8 @@ [rn/view {:style style/step-container} [quo/step {:in-blur-view? shell?} 3] - [rn/view - {:style style/step-content} - [rn/view - {:style style/step-title} + [rn/view {:style style/step-content} + [rn/view {:style style/step-title} [quo/text {:size :paragraph-2} (str (i18n/label :t/sign-up) " ")] [quo/text {:size :paragraph-2 :weight :semi-bold} (i18n/label :t/forgot-your-password-info-signup-with-key)]] @@ -45,8 +41,7 @@ [rn/view {:style style/step-container} [quo/step {:in-blur-view? shell?} 4] - [rn/view - {:style style/step-content} + [rn/view {:style style/step-content} [quo/text {:size :paragraph-2 :weight :semi-bold} (i18n/label :t/forgot-your-password-info-create-new-password)] [quo/text {:size :paragraph-2} diff --git a/src/status_im/contexts/chat/home/chat_list_item/view.cljs b/src/status_im/contexts/chat/home/chat_list_item/view.cljs index 7b59a7db2b20..729bc2979efe 100644 --- a/src/status_im/contexts/chat/home/chat_list_item/view.cljs +++ b/src/status_im/contexts/chat/home/chat_list_item/view.cljs @@ -276,8 +276,7 @@ (defn chat-user [item] - [rn/view - {:style (merge style/container {:margin-horizontal 0})} + [rn/view {:style (assoc style/container :margin-horizontal 0)} [chat-item item]]) (defn chat-list-item diff --git a/src/status_im/contexts/chat/home/view.cljs b/src/status_im/contexts/chat/home/view.cljs index 7cfa873d7110..54b40b78dc6c 100644 --- a/src/status_im/contexts/chat/home/view.cljs +++ b/src/status_im/contexts/chat/home/view.cljs @@ -62,8 +62,8 @@ :on-end-reached #(re-frame/dispatch [:chat/show-more-chats]) :keyboard-should-persist-taps :always :data items - :render-fn (fn [item] - (chat-list-item/chat-list-item item theme)) + :render-data {:theme theme} + :render-fn chat-list-item/chat-list-item :scroll-event-throttle 8 :content-container-style {:padding-bottom shell.constants/floating-shell-button-height @@ -94,8 +94,7 @@ {:selected-tab :tab/contacts :tab->content (empty-state-content theme)}] [rn/section-list - {:ref (when (not-empty items) - set-scroll-ref) + {:ref (when (seq items) set-scroll-ref) :key-fn :public-key :get-item-layout get-item-layout :content-inset-adjustment-behavior :never @@ -108,8 +107,8 @@ :sticky-section-headers-enabled false :render-section-header-fn contact-list/contacts-section-header :render-section-footer-fn contact-list/contacts-section-footer - :render-fn (fn [data] - (contact-item-render data theme)) + :render-data {:theme theme} + :render-fn contact-item-render :scroll-event-throttle 8 :on-scroll #(common.banner/set-scroll-shared-value {:scroll-input (oops/oget % "nativeEvent.contentOffset.y") diff --git a/src/status_im/contexts/profile/settings/header/header_shape.cljs b/src/status_im/contexts/profile/settings/header/header_shape.cljs index 71322e324b61..3f1d17e3c123 100644 --- a/src/status_im/contexts/profile/settings/header/header_shape.cljs +++ b/src/status_im/contexts/profile/settings/header/header_shape.cljs @@ -19,7 +19,7 @@ {:d "M20 20V0H0C11 0 20 9 20 20Z" :fill background-color}]]) -(defn f-view +(defn view [{:keys [scroll-y customization-color theme]}] (let [background-color (colors/resolve-color customization-color theme 40) opacity-animation (reanimated/interpolate scroll-y @@ -30,7 +30,3 @@ [reanimated/view {:style (style/radius-container opacity-animation)} [left-radius background-color] [right-radius background-color]]])) - -(defn view - [props] - [:f> f-view props]) diff --git a/src/status_im/contexts/profile/settings/header/style.cljs b/src/status_im/contexts/profile/settings/header/style.cljs index 2a2bff1b0720..52a60b59e07c 100644 --- a/src/status_im/contexts/profile/settings/header/style.cljs +++ b/src/status_im/contexts/profile/settings/header/style.cljs @@ -1,11 +1,11 @@ -(ns status-im.contexts.profile.settings.header.style) +(ns status-im.contexts.profile.settings.header.style + (:require [quo.foundations.colors :as colors] + [react-native.platform :as platform])) (def avatar-row-wrapper - {:display :flex - :padding-left 20 + {:padding-left 20 :padding-right 12 - :margin-top -60 - :margin-bottom -4 + :margin-top -65 :align-items :flex-end :justify-content :space-between :flex-direction :row}) @@ -21,3 +21,9 @@ {:opacity opacity-animation :flex-direction :row :justify-content :space-between}) + +(defn avatar-border-color + [theme] + (if platform/android? + colors/neutral-80-opa-80 ;; Fix is not needed because Android doesn't use blur + (colors/theme-colors colors/border-avatar-light colors/neutral-80-opa-80 theme))) diff --git a/src/status_im/contexts/profile/settings/header/view.cljs b/src/status_im/contexts/profile/settings/header/view.cljs index 19376d342ef7..2cc2797c5cdd 100644 --- a/src/status_im/contexts/profile/settings/header/view.cljs +++ b/src/status_im/contexts/profile/settings/header/view.cljs @@ -1,6 +1,5 @@ (ns status-im.contexts.profile.settings.header.view (:require [quo.core :as quo] - [quo.foundations.colors :as colors] [quo.theme] [react-native.core :as rn] [status-im.common.scalable-avatar.view :as avatar] @@ -11,49 +10,46 @@ [status-im.contexts.profile.utils :as profile.utils] [utils.re-frame :as rf])) +(defn- on-state-dropdown-press + [] + (rf/dispatch [:show-bottom-sheet + {:shell? true + :theme :dark + :content visibility-sheet/view}])) + (defn view [{:keys [scroll-y]}] - (let [theme (quo.theme/use-theme) - app-theme (rf/sub [:theme]) - {:keys [public-key emoji-hash bio] :as profile} (rf/sub [:profile/profile-with-image]) - online? (rf/sub [:visibility-status-updates/online? - public-key]) - status (rf/sub - [:visibility-status-updates/visibility-status-update - public-key]) - customization-color (rf/sub [:profile/customization-color]) - full-name (profile.utils/displayed-name profile) - profile-picture (profile.utils/photo profile) - {:keys [status-title status-icon]} (header.utils/visibility-status-type-data status) - border-theme app-theme] + (let [app-theme (rf/sub [:theme]) + {:keys [public-key emoji-hash bio] + :as profile} (rf/sub [:profile/profile-with-image]) + online? (rf/sub [:visibility-status-updates/online? public-key]) + status (rf/sub [:visibility-status-updates/visibility-status-update public-key]) + customization-color (rf/sub [:profile/customization-color]) + full-name (profile.utils/displayed-name profile) + profile-picture (profile.utils/photo profile) + {:keys [status-title + status-icon]} (header.utils/visibility-status-type-data status)] [:<> [header.shape/view {:scroll-y scroll-y - :customization-color customization-color - :theme theme}] + :customization-color customization-color}] [rn/view {:style style/avatar-row-wrapper} [avatar/view {:scroll-y scroll-y - :display-name full-name + :full-name full-name :online? online? - :border-color (colors/theme-colors colors/border-avatar-light - colors/neutral-80-opa-80 - border-theme) + :border-color (style/avatar-border-color app-theme) :customization-color customization-color :profile-picture profile-picture}] - [rn/view {:style {:margin-bottom 4}} - [quo/dropdown - {:background :blur - :size :size-32 - :type :outline - :icon? true - :no-icon-color? true - :icon-name status-icon - :on-press #(rf/dispatch [:show-bottom-sheet - {:shell? true - :theme :dark - :content (fn [] [visibility-sheet/view])}])} - status-title]]] + [quo/dropdown + {:background :blur + :size :size-32 + :type :outline + :icon? true + :no-icon-color? true + :icon-name status-icon + :on-press on-state-dropdown-press} + status-title]] [quo/page-top {:title-accessibility-label :username :emoji-dash emoji-hash diff --git a/src/status_im/contexts/profile/settings/view.cljs b/src/status_im/contexts/profile/settings/view.cljs index d74449a3bf81..a9c78955fa3f 100644 --- a/src/status_im/contexts/profile/settings/view.cljs +++ b/src/status_im/contexts/profile/settings/view.cljs @@ -1,7 +1,7 @@ (ns status-im.contexts.profile.settings.view (:require [oops.core :as oops] [quo.core :as quo] - [quo.theme :as quo.theme] + [quo.theme] [react-native.core :as rn] [react-native.reanimated :as reanimated] [react-native.safe-area :as safe-area] From 874aa9866d8d13f1fa8b4b60154e6f7eeb461647 Mon Sep 17 00:00:00 2001 From: Parvesh Monu Date: Thu, 9 Jan 2025 18:22:37 +0530 Subject: [PATCH 09/15] On-boarding: re add bio-metric screen to syncing flow (#21890) --- .../centralized_metrics/tracking.cljs | 2 +- .../onboarding/enable_biometrics/view.cljs | 9 +- src/status_im/contexts/onboarding/events.cljs | 16 +--- .../onboarding/syncing/progress/view.cljs | 37 ++++---- .../onboarding/syncing/results/style.cljs | 43 ---------- .../onboarding/syncing/results/view.cljs | 84 ------------------- .../contexts/profile/login/events.cljs | 31 +++---- src/status_im/navigation/roots.cljs | 7 +- src/status_im/navigation/screens.cljs | 11 +-- 9 files changed, 45 insertions(+), 195 deletions(-) delete mode 100644 src/status_im/contexts/onboarding/syncing/results/style.cljs delete mode 100644 src/status_im/contexts/onboarding/syncing/results/view.cljs diff --git a/src/status_im/contexts/centralized_metrics/tracking.cljs b/src/status_im/contexts/centralized_metrics/tracking.cljs index ac0d9102c418..6606235fca88 100644 --- a/src/status_im/contexts/centralized_metrics/tracking.cljs +++ b/src/status_im/contexts/centralized_metrics/tracking.cljs @@ -52,7 +52,7 @@ (contains? view-ids-to-track view-id) (conj (navigation-event (name view-id))) - (= :screen/onboarding.syncing-results view-id) + (#{:screen/onboarding.preparing-status :screen/onboarding.syncing-biometric} view-id) (conj (key-value-event "onboarding-completed")) (= :screen/keycard.migrate.success view-id) diff --git a/src/status_im/contexts/onboarding/enable_biometrics/view.cljs b/src/status_im/contexts/onboarding/enable_biometrics/view.cljs index cc59f2d1b299..228aa3a537c5 100644 --- a/src/status_im/contexts/onboarding/enable_biometrics/view.cljs +++ b/src/status_im/contexts/onboarding/enable_biometrics/view.cljs @@ -6,7 +6,6 @@ [status-im.common.biometric.utils :as biometric] [status-im.common.resources :as resources] [status-im.contexts.onboarding.enable-biometrics.style :as style] - [status-im.navigation.state :as state] [utils.i18n :as i18n] [utils.re-frame :as rf])) @@ -25,7 +24,7 @@ bio-type-label (biometric/get-label-by-type supported-biometric-type) profile-color (or (:color (rf/sub [:onboarding/profile])) (rf/sub [:profile/customization-color])) - syncing-results? (= :screen/onboarding.syncing-results @state/root-id) + syncing? (= (rf/sub [:view-id]) :screen/onboarding.syncing-biometric) biometric-type (rf/sub [:biometrics/supported-type])] [rn/view {:style (style/buttons insets)} [quo/button @@ -39,10 +38,8 @@ {:accessibility-label :maybe-later-button :background :blur :type :grey - :on-press #(rf/dispatch (if syncing-results? - [:navigate-to-within-stack - [:screen/onboarding.enable-notifications - :screen/onboarding.enable-biometrics]] + :on-press #(rf/dispatch (if syncing? + [:onboarding/finish-onboarding false] [:onboarding/create-account-and-login])) :container-style {:margin-top 12}} (i18n/label :t/maybe-later)]])) diff --git a/src/status_im/contexts/onboarding/events.cljs b/src/status_im/contexts/onboarding/events.cljs index 3bce2325b34d..72f0006fa048 100644 --- a/src/status_im/contexts/onboarding/events.cljs +++ b/src/status_im/contexts/onboarding/events.cljs @@ -38,12 +38,6 @@ (fn [{:keys [db]}] {:db (dissoc db :onboarding/navigated-to-enter-seed-phrase-from-screen)})) -(rf/reg-event-fx :onboarding/navigate-to-enable-notifications-from-syncing - (fn [{:keys [db]}] - {:db (dissoc db :onboarding/profile) - :dispatch [:navigate-to-within-stack - [:screen/onboarding.enable-notifications :screen/onboarding.enable-biometrics]]})) - (rf/reg-event-fx :onboarding/navigate-to-enable-notifications (fn [{:keys [db]}] {:dispatch [:navigate-to-within-stack @@ -113,14 +107,6 @@ [:navigate-to-within-stack [:screen/onboarding.enable-biometrics from-screen]] [:onboarding/create-account-and-login])]]}))) -(rf/reg-event-fx - :onboarding/navigate-to-enable-biometrics - (fn [{:keys [db]}] - (let [supported-type (get-in db [:biometrics :supported-type])] - {:dispatch (if supported-type - [:open-modal :screen/onboarding.enable-biometrics] - [:open-modal :screen/onboarding.enable-notifications])}))) - (rf/reg-event-fx :onboarding/seed-phrase-validated (fn [{:keys [db]} [seed-phrase key-uid]] @@ -200,7 +186,7 @@ (rf/dispatch [:onboarding/set-auth-method auth-method]) (when syncing? (rf/dispatch - [:onboarding/navigate-to-enable-notifications-from-syncing]))) + [:onboarding/finish-onboarding false]))) :on-error #(log/error "failed to save biometrics" {:key-uid key-uid :error %})}])]}))) diff --git a/src/status_im/contexts/onboarding/syncing/progress/view.cljs b/src/status_im/contexts/onboarding/syncing/progress/view.cljs index dc4916929d0e..7052ca305ef6 100644 --- a/src/status_im/contexts/onboarding/syncing/progress/view.cljs +++ b/src/status_im/contexts/onboarding/syncing/progress/view.cljs @@ -41,24 +41,25 @@ (defn try-again-button [profile-color logged-in?] - [quo/bottom-actions - {:actions (if logged-in? :one-action :two-vertical-actions) - :blur? true - :container-style {:height (when-not logged-in? 116)} - :button-two-label (i18n/label :t/use-recovery-phrase) - :button-two-props {:type :primary - :accessibility-label :try-seed-phrase-button - :customization-color profile-color - :size 40 - :on-press navigate-to-enter-seed-phrase} - :button-one-label - (i18n/label :t/try-again) - :button-one-props - {:type (if logged-in? :primary :grey) - :accessibility-label :try-again-later-button - :customization-color profile-color - :size 40 - :on-press #(try-again logged-in?)}}]) + (let [two-vertical-actions-height 116] + [quo/bottom-actions + {:actions (if logged-in? :one-action :two-vertical-actions) + :blur? true + :container-style {:height (when-not logged-in? two-vertical-actions-height)} + :button-two-label (i18n/label :t/use-recovery-phrase) + :button-two-props {:type :primary + :accessibility-label :try-seed-phrase-button + :customization-color profile-color + :size 40 + :on-press navigate-to-enter-seed-phrase} + :button-one-label + (i18n/label :t/try-again) + :button-one-props + {:type (if logged-in? :primary :grey) + :accessibility-label :try-again-later-button + :customization-color profile-color + :size 40 + :on-press #(try-again logged-in?)}}])) (defn- illustration [pairing-progress?] diff --git a/src/status_im/contexts/onboarding/syncing/results/style.cljs b/src/status_im/contexts/onboarding/syncing/results/style.cljs deleted file mode 100644 index 7b65dc0ce039..000000000000 --- a/src/status_im/contexts/onboarding/syncing/results/style.cljs +++ /dev/null @@ -1,43 +0,0 @@ -(ns status-im.contexts.onboarding.syncing.results.style - (:require - [quo.foundations.colors :as colors] - [react-native.reanimated :as reanimated])) - -(def absolute-fill - {:position :absolute - :top 0 - :bottom 0 - :left 0 - :right 0}) - -(defn page-container - [top] - {:flex 1 - :position :absolute - :top 0 - :bottom 0 - :left 0 - :right 0 - :padding-top top - :padding-bottom 20 - :background-color colors/neutral-80-opa-80-blur}) - -(defn content - [translate-x] - (reanimated/apply-animations-to-style - {:transform [{:translate-x translate-x}]} - {:margin-top 56 - :margin-bottom 26 - :flex 1})) - -(def current-device - {:margin-bottom 19}) - -(def device-list - {:flex 1 - :margin-top 12 - :padding-horizontal 20}) - -(def continue-button - {:margin-top 20 - :padding-horizontal 20}) diff --git a/src/status_im/contexts/onboarding/syncing/results/view.cljs b/src/status_im/contexts/onboarding/syncing/results/view.cljs deleted file mode 100644 index 125c17b61e84..000000000000 --- a/src/status_im/contexts/onboarding/syncing/results/view.cljs +++ /dev/null @@ -1,84 +0,0 @@ -(ns status-im.contexts.onboarding.syncing.results.view - (:require - [quo.core :as quo] - [quo.foundations.colors :as colors] - [react-native.core :as rn] - [react-native.reanimated :as reanimated] - [react-native.safe-area :as safe-area] - [status-im.constants :as constants] - [status-im.contexts.onboarding.common.background.view :as background] - [status-im.contexts.onboarding.syncing.results.style :as style] - [status-im.contexts.syncing.device.view :as device] - [utils.i18n :as i18n] - [utils.re-frame :as rf])) - -(defn page-title - [] - [quo/text-combinations - {:container-style {:margin-horizontal 20} - :title (i18n/label :t/sync-devices-complete-title) - :title-accessibility-label :sync-devices-title - :description (i18n/label :t/sync-devices-complete-sub-title) - :description-accessibility-label :sync-devices-complete-sub-title}]) - -(defn current-device - [installation] - [rn/view {:style style/current-device} - [device/view - (merge installation - {:this-device? true})]]) - -(defn devices-list - [] - (let [installations (rf/sub [:pairing/enabled-installations]) - this-device (first installations) - other-devices (rest installations)] - [rn/view {:style style/device-list} - [current-device this-device] - [quo/text - {:accessibility-label :synced-with-sub-title - :weight :regular - :size :paragraph-2 - :style {:color colors/white-opa-40}} - (i18n/label :t/synced-with)] - [rn/flat-list - {:data other-devices - :shows-vertical-scroll-indicator false - :key-fn :installation-id - :render-fn device/view}]])) - -(defn continue-button - [on-press] - (let [profile-color (rf/sub [:profile/customization-color])] - [quo/button - {:on-press (fn [] - (when on-press - (on-press)) - (rf/dispatch [:onboarding/navigate-to-enable-biometrics])) - :accessibility-label :continue-button - :customization-color profile-color - :container-style style/continue-button} - (i18n/label :t/continue)])) - -(defn- f-view - [] - (let [top (safe-area/get-top) - translate-x (reanimated/use-shared-value 0) - window-width (:width (rn/get-window))] - [rn/view {:style (style/page-container top)} - [rn/view {:style style/absolute-fill} - [background/view true]] - [reanimated/view - {:style (style/content translate-x)} - [page-title] - [devices-list] - [continue-button - #(reanimated/animate-shared-value-with-delay translate-x - (- window-width) - constants/onboarding-modal-animation-duration - :linear - 200)]]])) - -(defn view - [] - [:f> f-view]) diff --git a/src/status_im/contexts/profile/login/events.cljs b/src/status_im/contexts/profile/login/events.cljs index 189c77deb942..8d7e21968d23 100644 --- a/src/status_im/contexts/profile/login/events.cljs +++ b/src/status_im/contexts/profile/login/events.cljs @@ -37,18 +37,19 @@ ;; login phase 1: we want to load and show chats faster, so we split login into 2 phases (rf/reg-event-fx :profile.login/login-existing-profile (fn [{:keys [db]} [settings-data account]] - (let [settings (data-store.settings/rpc->settings settings-data) - profile-overview (profile.rpc/rpc->profiles-overview account) - log-level (or (:log-level settings) config/log-level) - pairing-completed? (= (get-in db [:syncing :pairing-status]) :completed) - new-db (-> db - (assoc :profile/profile - (merge profile-overview - settings - {:log-level log-level})) - (assoc-in [:activity-center :loading?] true) - (dissoc :centralized-metrics/onboarding-enabled?)) - keycard? (get-in new-db [:profile/profile :keycard-pairing])] + (let [settings (data-store.settings/rpc->settings settings-data) + profile-overview (profile.rpc/rpc->profiles-overview account) + log-level (or (:log-level settings) config/log-level) + pairing-completed? (= (get-in db [:syncing :pairing-status]) :completed) + biometric-supported-type (get-in db [:biometrics :supported-type]) + new-db (-> db + (assoc :profile/profile + (merge profile-overview + settings + {:log-level log-level})) + (assoc-in [:activity-center :loading?] true) + (dissoc :centralized-metrics/onboarding-enabled?)) + keycard? (get-in new-db [:profile/profile :keycard-pairing])] {:db (cond-> new-db pairing-completed? (dissoc :syncing)) :fx (into [[:json-rpc/call @@ -81,10 +82,10 @@ (when keycard? [:dispatch [:centralized-metrics/track :metric/keycard-login]])] (cond - pairing-completed? - [[:dispatch [:onboarding/finish-onboarding false]]] + (and pairing-completed? biometric-supported-type) + [[:dispatch [:update-theme-and-init-root :screen/onboarding.syncing-biometric]]] - (get db :onboarding/new-account?) + (or pairing-completed? (get db :onboarding/new-account?)) [[:dispatch [:onboarding/finalize-setup]] [:dispatch [:onboarding/finish-onboarding false]]] diff --git a/src/status_im/navigation/roots.cljs b/src/status_im/navigation/roots.cljs index 33e49ca36f28..a1a46de948d3 100644 --- a/src/status_im/navigation/roots.cljs +++ b/src/status_im/navigation/roots.cljs @@ -26,9 +26,10 @@ :id :screen/profile.profiles :options (options/dark-root-options)}}]}}} - :screen/onboarding.syncing-results - {:root {:stack {:children [{:component {:name :screen/onboarding.syncing-results - :id :screen/onboarding.syncing-results + :screen/onboarding.syncing-biometric + {:root {:stack {:id :screen/onboarding.enable-biometrics + :children [{:component {:name :screen/onboarding.enable-biometrics + :id :screen/onboarding.enable-biometrics :options (options/dark-root-options)}}]}}}}) (defn old-roots diff --git a/src/status_im/navigation/screens.cljs b/src/status_im/navigation/screens.cljs index 7e6fd15aac85..ecbc2c7870e7 100644 --- a/src/status_im/navigation/screens.cljs +++ b/src/status_im/navigation/screens.cljs @@ -53,7 +53,6 @@ [status-im.contexts.onboarding.share-usage.view :as onboarding.share-usage] [status-im.contexts.onboarding.sign-in.view :as sign-in] [status-im.contexts.onboarding.syncing.progress.view :as syncing-devices] - [status-im.contexts.onboarding.syncing.results.view :as syncing-results] [status-im.contexts.preview.feature-flags.view :as feature-flags] [status-im.contexts.preview.quo.component-preview.view :as component-preview] [status-im.contexts.preview.quo.main :as quo.preview] @@ -855,13 +854,6 @@ :popGesture false} :component syncing-devices/view-onboarding}) -(def onboarding-syncing-results - {:name :screen/onboarding.syncing-results - :metrics {:track? true - :alias-id :onboarding.syncing-completed} - :options {:theme :dark} - :component syncing-results/view}) - (def onboarding-screens [onboarding-intro onboarding-create-profile @@ -875,8 +867,7 @@ onboarding-sign-in-intro onboarding-sign-in onboarding-syncing-progress - onboarding-syncing-progress-intro - onboarding-syncing-results]) + onboarding-syncing-progress-intro]) (def keycard-screens [{:name :screen/keycard.check From 770963447a45d984028a49a2e72447fad9cae297 Mon Sep 17 00:00:00 2001 From: Volodymyr Kozieiev Date: Thu, 9 Jan 2025 13:48:10 +0000 Subject: [PATCH 10/15] Simplified pull request template (#21900) --- .github/PULL_REQUEST_TEMPLATE.md | 50 ++++++++++---------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f9c465378b23..e0c1425a1a7c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,39 +1,26 @@ -[comment]: # (Please replace ... with your information. Remove < and >) [comment]: # (To auto-close issue on merge, please insert the related issue number after # i.e fixes #566) - -If you submit PR for issue with bounty then write here Fixes #NN where NN is issue number - -*otherwise* - fixes #... -### Summary - +## Summary [comment]: # (Summarise the problem and how the pull request solves it) ... - -Documentation change PR (review please): https://github.com/status-im/status.im/pull/xxx - -### Review notes - +## Review notes +[comment]: # (Optional. Specify if something in particular should be looked at, or ignored, during review) -### Testing notes - +## Testing notes +[comment]: # (Optional) -#### Platforms - +### Platforms +[comment]: # (Optional. Specify which platforms should be tested) - Android - iOS -- macOS -- Linux -- Windows -#### Areas that maybe impacted - +### Areas that may be impacted +[comment]: # (Optional. Specify if some specific areas need to be tested, such as 1-1 chats) -##### Functional +#### Functional - 1-1 chats - public chats @@ -48,32 +35,27 @@ Documentation change PR (review please): https://github.com/status-im/status.im/ - fleet - bootnodes -##### Non-functional +#### Non-functional - battery performance - CPU performance / speed of the app - network consumption -### Steps to test - +## Steps to test +[comment]: # (Specify exact steps to test if there are such) - Open Status - ... - Step 3, etc. - - -### Before and after screenshots comparison -| Figma (if available) | iOS (if available) | Android (if available) -| --- | --- | --- | -| Please embed Image/Video here of the before and after. | Please embed Image/Video here of the before and after. | Please embed Image/Video here of the before and after. | +[comment]: # (Can be ready or wip) +status: ready -status: ready