🦁 Fix issues with missing dapp images and dapp names (#20811)
* 🦁 Beast mode * 🗑️ Remove `prn` calls * 🌎 Add utils to remove http:// prefix * ⏭️ Extracted name and avatar computation * 🧹 Cleanup * ✏️ Fix lint and remove REPL flow * ❌ Remove broken test * 🖊️ Fix lint
This commit is contained in:
parent
1a4987478c
commit
3bb7c308e3
|
@ -47,3 +47,12 @@
|
||||||
(defn style-text-value
|
(defn style-text-value
|
||||||
[theme]
|
[theme]
|
||||||
{:color (colors/theme-colors colors/neutral-50 colors/white theme)})
|
{:color (colors/theme-colors colors/neutral-50 colors/white theme)})
|
||||||
|
|
||||||
|
(def initials-avatar-container
|
||||||
|
{:width 32
|
||||||
|
:height 32})
|
||||||
|
|
||||||
|
(def image-avatar
|
||||||
|
{:width 32
|
||||||
|
:height 32
|
||||||
|
:border-radius 32})
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
(ns quo.components.list-items.dapp.view
|
(ns quo.components.list-items.dapp.view
|
||||||
(:require
|
(:require
|
||||||
|
[quo.components.avatars.user-avatar.view :as user-avatar]
|
||||||
[quo.components.list-items.dapp.style :as style]
|
[quo.components.list-items.dapp.style :as style]
|
||||||
[quo.components.markdown.text :as text]
|
[quo.components.markdown.text :as text]
|
||||||
[quo.theme :as quo.theme]
|
[quo.theme :as quo.theme]
|
||||||
|
@ -20,9 +21,15 @@
|
||||||
:on-press-in on-press-in
|
:on-press-in on-press-in
|
||||||
:on-press-out on-press-out}
|
:on-press-out on-press-out}
|
||||||
[rn/view {:style style/container-info}
|
[rn/view {:style style/container-info}
|
||||||
|
(if (:avatar dapp)
|
||||||
[fast-image/fast-image
|
[fast-image/fast-image
|
||||||
{:source (:avatar dapp)
|
{:source (:avatar dapp)
|
||||||
:style {:width 32 :height 32}}]
|
:style style/image-avatar}]
|
||||||
|
[rn/view {:style style/initials-avatar-container}
|
||||||
|
[user-avatar/initials-avatar
|
||||||
|
{:full-name (:name dapp)
|
||||||
|
:size :small
|
||||||
|
:customization-color (:customization-color dapp)}]])
|
||||||
[rn/view {:style style/user-info}
|
[rn/view {:style style/user-info}
|
||||||
[text/text
|
[text/text
|
||||||
{:weight :semi-bold
|
{:weight :semi-bold
|
||||||
|
|
|
@ -13,14 +13,17 @@
|
||||||
:value "Default"}
|
:value "Default"}
|
||||||
{:key :active
|
{:key :active
|
||||||
:value "Active"}]}
|
:value "Active"}]}
|
||||||
{:key :action
|
{:key :dapp
|
||||||
:type :select
|
:type :select
|
||||||
:options [{:key :none
|
:options [{:value "With icon"
|
||||||
:value "None"}
|
:key {:avatar (resources/get-dapp :coingecko)
|
||||||
{:key :icon
|
:name "Coingecko"
|
||||||
:value "Icon"}]}
|
:value "coingecko.com"}}
|
||||||
{:key :blur?
|
{:value "Without icon"
|
||||||
:type :boolean}])
|
:key {:avatar nil
|
||||||
|
:name "Coingecko"
|
||||||
|
:value "coingecko.com"
|
||||||
|
:customization-color :blue}}]}])
|
||||||
|
|
||||||
(defn preview
|
(defn preview
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -9,8 +9,10 @@
|
||||||
[status-im.common.resources :as resources]
|
[status-im.common.resources :as resources]
|
||||||
[status-im.contexts.wallet.connected-dapps.disconnect-dapp.view :as disconnect-dapp]
|
[status-im.contexts.wallet.connected-dapps.disconnect-dapp.view :as disconnect-dapp]
|
||||||
[status-im.contexts.wallet.connected-dapps.style :as style]
|
[status-im.contexts.wallet.connected-dapps.style :as style]
|
||||||
|
[status-im.contexts.wallet.wallet-connect.core :as core]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]
|
||||||
|
[utils.string]))
|
||||||
|
|
||||||
(defn- on-disconnect
|
(defn- on-disconnect
|
||||||
[wallet-account {:keys [name topic]}]
|
[wallet-account {:keys [name topic]}]
|
||||||
|
@ -84,7 +86,8 @@
|
||||||
{:keys [color] :as wallet-account} (rf/sub [:wallet/current-viewing-account])
|
{:keys [color] :as wallet-account} (rf/sub [:wallet/current-viewing-account])
|
||||||
sessions (rf/sub
|
sessions (rf/sub
|
||||||
[:wallet-connect/sessions-for-current-account])
|
[:wallet-connect/sessions-for-current-account])
|
||||||
theme (quo.theme/use-theme)]
|
theme (quo.theme/use-theme)
|
||||||
|
customization-color (rf/sub [:profile/customization-color])]
|
||||||
[rn/view {:flex 1}
|
[rn/view {:flex 1}
|
||||||
[header
|
[header
|
||||||
{:title (i18n/label :t/connected-dapps)
|
{:title (i18n/label :t/connected-dapps)
|
||||||
|
@ -104,11 +107,13 @@
|
||||||
:content-container-style (style/dapps-list theme)
|
:content-container-style (style/dapps-list theme)
|
||||||
:render-fn (fn [{:keys [topic pairingTopic name url iconUrl]}]
|
:render-fn (fn [{:keys [topic pairingTopic name url iconUrl]}]
|
||||||
[quo/dapp
|
[quo/dapp
|
||||||
{:dapp {:avatar iconUrl
|
{:dapp {:avatar (core/compute-dapp-icon-path iconUrl
|
||||||
:name name
|
url)
|
||||||
|
:name (core/compute-dapp-name name url)
|
||||||
:value url
|
:value url
|
||||||
:topic topic
|
:topic topic
|
||||||
:pairing-topic pairingTopic}
|
:pairing-topic pairingTopic
|
||||||
|
:customization-color customization-color}
|
||||||
:accessibility-label (str "dapp-" topic)
|
:accessibility-label (str "dapp-" topic)
|
||||||
:state :default
|
:state :default
|
||||||
:action :icon
|
:action :icon
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
[native-module.core :as native-module]
|
[native-module.core :as native-module]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[utils.security.core :as security]
|
[utils.security.core :as security]
|
||||||
|
[utils.string]
|
||||||
[utils.transforms :as transforms]))
|
[utils.transforms :as transforms]))
|
||||||
|
|
||||||
(def method-to-screen
|
(def method-to-screen
|
||||||
|
@ -143,3 +144,23 @@
|
||||||
account-addresses))
|
account-addresses))
|
||||||
accounts))
|
accounts))
|
||||||
sessions))
|
sessions))
|
||||||
|
|
||||||
|
(defn compute-dapp-name
|
||||||
|
"Sometimes dapps have no name or an empty name. Return url as name in that case"
|
||||||
|
[name url]
|
||||||
|
(if (seq name)
|
||||||
|
name
|
||||||
|
(when (seq url)
|
||||||
|
(-> url
|
||||||
|
utils.string/remove-trailing-slash
|
||||||
|
utils.string/remove-http-prefix
|
||||||
|
string/capitalize))))
|
||||||
|
|
||||||
|
(defn compute-dapp-icon-path
|
||||||
|
"Some dapps have icons with relative paths, make paths absolute in those cases, send nil if icon is missing"
|
||||||
|
[icon-path url]
|
||||||
|
(when (and (seq icon-path)
|
||||||
|
(seq url))
|
||||||
|
(if (string/starts-with? icon-path "http")
|
||||||
|
icon-path
|
||||||
|
(str (utils.string/remove-trailing-slash url) icon-path))))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
(ns status-im.contexts.wallet.wallet-connect.modals.common.footer.view
|
(ns status-im.contexts.wallet.wallet-connect.modals.common.footer.view
|
||||||
(:require [quo.core :as quo]
|
(:require [quo.core :as quo]
|
||||||
[quo.foundations.colors :as colors]
|
[quo.foundations.colors :as colors]
|
||||||
|
[quo.theme]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[status-im.common.standard-authentication.core :as standard-authentication]
|
[status-im.common.standard-authentication.core :as standard-authentication]
|
||||||
[status-im.contexts.wallet.wallet-connect.modals.common.footer.style :as style]
|
[status-im.contexts.wallet.wallet-connect.modals.common.footer.style :as style]
|
||||||
|
@ -14,7 +15,8 @@
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[{:keys [warning-label slide-button-text disabled?]} & children]
|
[{:keys [warning-label slide-button-text disabled?]} & children]
|
||||||
(let [{:keys [customization-color]} (rf/sub [:wallet-connect/current-request-account-details])]
|
(let [{:keys [customization-color]} (rf/sub [:wallet-connect/current-request-account-details])
|
||||||
|
theme (quo.theme/use-theme)]
|
||||||
[rn/view {:style style/content-container}
|
[rn/view {:style style/content-container}
|
||||||
(into [rn/view
|
(into [rn/view
|
||||||
{:style style/data-items-container}]
|
{:style style/data-items-container}]
|
||||||
|
@ -30,6 +32,8 @@
|
||||||
[rn/view {:style style/warning-container}
|
[rn/view {:style style/warning-container}
|
||||||
[quo/text
|
[quo/text
|
||||||
{:size :paragraph-2
|
{:size :paragraph-2
|
||||||
:style {:color colors/neutral-80-opa-70}
|
:style {:color (if (= theme :dark)
|
||||||
|
colors/white-opa-70
|
||||||
|
colors/neutral-80-opa-70)}
|
||||||
:weight :medium}
|
:weight :medium}
|
||||||
warning-label]]]))
|
warning-label]]]))
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
(ns status-im.contexts.wallet.wallet-connect.modals.common.header.view
|
(ns status-im.contexts.wallet.wallet-connect.modals.common.header.view
|
||||||
(:require [quo.core :as quo]
|
(:require
|
||||||
|
[quo.core :as quo]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[status-im.contexts.wallet.wallet-connect.modals.common.header.style :as style]))
|
[status-im.contexts.wallet.wallet-connect.core :as core]
|
||||||
|
[status-im.contexts.wallet.wallet-connect.modals.common.header.style :as style]
|
||||||
|
[utils.string]))
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[{:keys [label dapp account]}]
|
[{:keys [label dapp account]}]
|
||||||
|
@ -10,12 +13,13 @@
|
||||||
[quo/text
|
[quo/text
|
||||||
{:size :heading-1
|
{:size :heading-1
|
||||||
:weight :semi-bold}
|
:weight :semi-bold}
|
||||||
(let [{:keys [name iconUrl]} dapp]
|
(let [{:keys [name iconUrl url]} dapp
|
||||||
|
image-source (core/compute-dapp-icon-path iconUrl url)]
|
||||||
[rn/view {:style style/header-dapp-name}
|
[rn/view {:style style/header-dapp-name}
|
||||||
[quo/summary-tag
|
[quo/summary-tag
|
||||||
{:type :dapp
|
{:type :dapp
|
||||||
:label name
|
:label name
|
||||||
:image-source iconUrl}]])
|
:image-source image-source}]])
|
||||||
(str " " label " ")
|
(str " " label " ")
|
||||||
(let [{:keys [emoji customization-color name]} account]
|
(let [{:keys [emoji customization-color name]} account]
|
||||||
[rn/view {:style style/header-account-name}
|
[rn/view {:style style/header-account-name}
|
||||||
|
|
|
@ -5,14 +5,15 @@
|
||||||
{:padding-horizontal 20
|
{:padding-horizontal 20
|
||||||
:padding-top 12})
|
:padding-top 12})
|
||||||
|
|
||||||
(def approval-note-container
|
(defn approval-note-container
|
||||||
|
[theme]
|
||||||
{:margin-horizontal 20
|
{:margin-horizontal 20
|
||||||
:padding-horizontal 16
|
:padding-horizontal 16
|
||||||
:padding-vertical 12
|
:padding-vertical 12
|
||||||
:border-radius 16
|
:border-radius 16
|
||||||
:border-width 1
|
:border-width 1
|
||||||
:border-color colors/neutral-10
|
:border-color (colors/theme-colors colors/neutral-10 colors/black-opa-30 theme)
|
||||||
:background-color colors/neutral-2_5})
|
:background-color (colors/theme-colors colors/neutral-2_5 colors/black-opa-30 theme)})
|
||||||
|
|
||||||
(def approval-note-title
|
(def approval-note-title
|
||||||
{:color colors/neutral-50
|
{:color colors/neutral-50
|
||||||
|
|
|
@ -6,21 +6,27 @@
|
||||||
[quo.theme]
|
[quo.theme]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||||
|
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
|
||||||
[status-im.contexts.wallet.wallet-connect.session-proposal.style :as style]
|
[status-im.contexts.wallet.wallet-connect.session-proposal.style :as style]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]
|
||||||
|
[utils.string]))
|
||||||
|
|
||||||
(defn- dapp-metadata
|
(defn- dapp-metadata
|
||||||
[]
|
[]
|
||||||
(let [proposer (rf/sub [:wallet-connect/session-proposer])
|
(let [proposer (rf/sub [:wallet-connect/session-proposer])
|
||||||
{:keys [icons name url]} (:metadata proposer)]
|
{:keys [icons name url]} (:metadata proposer)
|
||||||
|
first-icon (first icons)
|
||||||
|
dapp-name (wallet-connect-core/compute-dapp-name name url)
|
||||||
|
profile-picture (wallet-connect-core/compute-dapp-icon-path first-icon url)]
|
||||||
[:<>
|
[:<>
|
||||||
[rn/view {:style style/dapp-avatar}
|
[rn/view {:style style/dapp-avatar}
|
||||||
[quo/user-avatar
|
[quo/user-avatar
|
||||||
{:profile-picture (first icons)
|
{:profile-picture profile-picture
|
||||||
:size :big}]]
|
:size :big
|
||||||
|
:full-name dapp-name}]]
|
||||||
[quo/page-top
|
[quo/page-top
|
||||||
{:title name
|
{:title dapp-name
|
||||||
:description :context-tag
|
:description :context-tag
|
||||||
:context-tag {:type :icon
|
:context-tag {:type :icon
|
||||||
:size 32
|
:size 32
|
||||||
|
@ -31,8 +37,9 @@
|
||||||
[]
|
[]
|
||||||
(let [dapp-name (rf/sub [:wallet-connect/session-proposer-name])
|
(let [dapp-name (rf/sub [:wallet-connect/session-proposer-name])
|
||||||
labels [(i18n/label :t/check-your-account-balance-and-activity)
|
labels [(i18n/label :t/check-your-account-balance-and-activity)
|
||||||
(i18n/label :t/request-txns-and-message-signing)]]
|
(i18n/label :t/request-txns-and-message-signing)]
|
||||||
[rn/view {:style style/approval-note-container}
|
theme (quo.theme/use-theme)]
|
||||||
|
[rn/view {:style (style/approval-note-container theme)}
|
||||||
[quo/text
|
[quo/text
|
||||||
{:style style/approval-note-title
|
{:style style/approval-note-title
|
||||||
:weight :regular
|
:weight :regular
|
||||||
|
@ -46,7 +53,8 @@
|
||||||
{:color colors/neutral-40}]
|
{:color colors/neutral-40}]
|
||||||
[quo/text
|
[quo/text
|
||||||
{:weight :regular
|
{:weight :regular
|
||||||
:size :paragraph-2}
|
:size :paragraph-2
|
||||||
|
:color colors/neutral-40}
|
||||||
label]])
|
label]])
|
||||||
labels)]))
|
labels)]))
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
[status-im.contexts.wallet.common.utils.networks :as networks]
|
[status-im.contexts.wallet.common.utils.networks :as networks]
|
||||||
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
|
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
|
||||||
[status-im.contexts.wallet.wallet-connect.transactions :as transactions]
|
[status-im.contexts.wallet.wallet-connect.transactions :as transactions]
|
||||||
[utils.money :as money]))
|
[utils.money :as money]
|
||||||
|
[utils.string]))
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
:wallet-connect/current-request-address
|
:wallet-connect/current-request-address
|
||||||
|
@ -44,7 +45,8 @@
|
||||||
(let [dapp-url (get-in request [:event :verifyContext :verified :origin])]
|
(let [dapp-url (get-in request [:event :verifyContext :verified :origin])]
|
||||||
(->> sessions
|
(->> sessions
|
||||||
(filter (fn [session]
|
(filter (fn [session]
|
||||||
(= dapp-url (get session :url))))
|
(= (utils.string/remove-trailing-slash dapp-url)
|
||||||
|
(utils.string/remove-trailing-slash (get session :url)))))
|
||||||
(first)))))
|
(first)))))
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
|
@ -168,7 +170,8 @@
|
||||||
:wallet-connect/session-proposer-name
|
:wallet-connect/session-proposer-name
|
||||||
:<- [:wallet-connect/session-proposer]
|
:<- [:wallet-connect/session-proposer]
|
||||||
(fn [proposer]
|
(fn [proposer]
|
||||||
(-> proposer :metadata :name)))
|
(let [{:keys [name url]} (-> proposer :metadata)]
|
||||||
|
(wallet-connect-core/compute-dapp-name name url))))
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
:wallet-connect/session-proposal-network-details
|
:wallet-connect/session-proposal-network-details
|
||||||
|
|
|
@ -42,6 +42,41 @@
|
||||||
:origin "https://lab.web3modal.com"
|
:origin "https://lab.web3modal.com"
|
||||||
:isScam false}}}})
|
: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
|
(h/deftest-sub :wallet-connect/session-proposer
|
||||||
[sub-name]
|
[sub-name]
|
||||||
(testing "Return the session proposer public key and metadata"
|
(testing "Return the session proposer public key and metadata"
|
||||||
|
|
|
@ -73,3 +73,18 @@
|
||||||
(defn contains-special-character?
|
(defn contains-special-character?
|
||||||
[s]
|
[s]
|
||||||
(re-find #"[^a-zA-Z0-9\s]" s))
|
(re-find #"[^a-zA-Z0-9\s]" s))
|
||||||
|
|
||||||
|
(defn remove-trailing-slash
|
||||||
|
"Given a URL, checks if it has a trailing slash and removes it.
|
||||||
|
Returns the URL as-is if there is no trailing slash."
|
||||||
|
[url]
|
||||||
|
(if (and (string? url) (string/ends-with? url "/"))
|
||||||
|
(subs url 0 (dec (count url)))
|
||||||
|
url))
|
||||||
|
|
||||||
|
(defn remove-http-prefix
|
||||||
|
"Given a URL, removes the 'http://' or 'https://' prefix if present.
|
||||||
|
Returns the URL without the prefix."
|
||||||
|
[url]
|
||||||
|
(when (string? url)
|
||||||
|
(string/replace url #"^https?://" "")))
|
||||||
|
|
|
@ -18,3 +18,25 @@
|
||||||
"AB" "a b" 2
|
"AB" "a b" 2
|
||||||
"ABC" "a b c d" 3
|
"ABC" "a b c d" 3
|
||||||
"ABC" " a b c d" 3))
|
"ABC" " a b c d" 3))
|
||||||
|
|
||||||
|
(deftest remove-trailing-slash-test
|
||||||
|
(are [expected input]
|
||||||
|
(= expected (utils.string/remove-trailing-slash input))
|
||||||
|
"http://example.com" "http://example.com/"
|
||||||
|
"http://example.com" "http://example.com"
|
||||||
|
"http://example.com/path" "http://example.com/path/"
|
||||||
|
"http://example.com/path" "http://example.com/path"
|
||||||
|
"" ""
|
||||||
|
nil nil))
|
||||||
|
|
||||||
|
(deftest remove-http-prefix-test
|
||||||
|
(are [expected input]
|
||||||
|
(= expected (utils.string/remove-http-prefix input))
|
||||||
|
"example.com" "http://example.com"
|
||||||
|
"example.com" "https://example.com"
|
||||||
|
"example.com" "example.com"
|
||||||
|
"example.com/path" "http://example.com/path"
|
||||||
|
"example.com/path" "https://example.com/path"
|
||||||
|
"example.com/path" "example.com/path"
|
||||||
|
"" ""
|
||||||
|
nil nil))
|
||||||
|
|
Loading…
Reference in New Issue