@fairmint/ui 0.2.14 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/specific/WalletList/WalletList.d.ts +35 -5
- package/dist/components/specific/WalletList/WalletList.d.ts.map +1 -1
- package/dist/fairmint-ui.cjs +277 -56
- package/dist/fairmint-ui.cjs.map +1 -1
- package/dist/fairmint-ui.js +277 -56
- package/dist/fairmint-ui.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/utils/wallets.d.ts +19 -0
- package/dist/utils/wallets.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/fairmint-ui.js
CHANGED
|
@@ -30688,38 +30688,84 @@ function InvestorProfileCard({
|
|
|
30688
30688
|
children
|
|
30689
30689
|
] });
|
|
30690
30690
|
}
|
|
30691
|
-
const
|
|
30691
|
+
const SYSTEM_TYPES = /* @__PURE__ */ new Set(["fairmint", "privy"]);
|
|
30692
|
+
const TYPE_LABELS = {
|
|
30692
30693
|
fairmint: "Fairmint Wallet",
|
|
30693
30694
|
privy: "Fairmint Wallet",
|
|
30694
30695
|
manual: "Manual"
|
|
30695
30696
|
};
|
|
30696
|
-
function
|
|
30697
|
-
|
|
30698
|
-
|
|
30697
|
+
function normalizeWalletType(type) {
|
|
30698
|
+
return String(type ?? "").trim().toLowerCase();
|
|
30699
|
+
}
|
|
30700
|
+
function getWalletLabel(type, custom2) {
|
|
30701
|
+
const key = normalizeWalletType(type);
|
|
30702
|
+
const rawType = typeof type === "string" ? type : String(type ?? "");
|
|
30703
|
+
if (custom2?.[key]) return custom2[key];
|
|
30704
|
+
if (custom2?.[rawType]) return custom2[rawType];
|
|
30705
|
+
return TYPE_LABELS[key] ?? rawType;
|
|
30706
|
+
}
|
|
30707
|
+
function getWalletDisplayName(wallet, customLabels) {
|
|
30708
|
+
const label = wallet.label?.trim();
|
|
30709
|
+
if (label) return label;
|
|
30710
|
+
return getWalletLabel(wallet.type, customLabels);
|
|
30711
|
+
}
|
|
30712
|
+
function isSystemWalletType(type) {
|
|
30713
|
+
return SYSTEM_TYPES.has(normalizeWalletType(type));
|
|
30714
|
+
}
|
|
30715
|
+
function isRemovableWalletType(type) {
|
|
30716
|
+
return !isSystemWalletType(type);
|
|
30717
|
+
}
|
|
30718
|
+
function walletKey(w) {
|
|
30719
|
+
return `${normalizeWalletType(w.type)}:${w.address.toLowerCase()}`;
|
|
30699
30720
|
}
|
|
30700
30721
|
function WalletList({
|
|
30701
30722
|
wallets,
|
|
30702
30723
|
onAdd,
|
|
30703
30724
|
onRemove,
|
|
30725
|
+
onSetDefault,
|
|
30726
|
+
onLabel,
|
|
30727
|
+
onConnect,
|
|
30728
|
+
getExplorerUrl,
|
|
30704
30729
|
readOnly = false,
|
|
30705
30730
|
addLoading = false,
|
|
30706
30731
|
removeLoading = false,
|
|
30732
|
+
setDefaultLoading = false,
|
|
30733
|
+
setDefaultAddress,
|
|
30734
|
+
labelLoading = false,
|
|
30735
|
+
labelAddress,
|
|
30736
|
+
connectLoading = false,
|
|
30707
30737
|
emptyIcon,
|
|
30708
30738
|
copyIcon,
|
|
30709
30739
|
copiedIcon,
|
|
30710
30740
|
removeIcon,
|
|
30711
30741
|
addIcon,
|
|
30742
|
+
defaultIcon,
|
|
30743
|
+
renameIcon,
|
|
30744
|
+
explorerIcon,
|
|
30745
|
+
connectIcon,
|
|
30712
30746
|
typeLabels,
|
|
30713
|
-
removableTypes
|
|
30747
|
+
removableTypes,
|
|
30748
|
+
children
|
|
30714
30749
|
}) {
|
|
30750
|
+
const normalizeWalletAddress = useCallback(
|
|
30751
|
+
(address) => address?.trim().toLowerCase() ?? "",
|
|
30752
|
+
[]
|
|
30753
|
+
);
|
|
30715
30754
|
const [newAddress, setNewAddress] = useState("");
|
|
30716
30755
|
const [addressError, setAddressError] = useState(null);
|
|
30717
30756
|
const [showAddForm, setShowAddForm] = useState(false);
|
|
30718
30757
|
const [walletToRemove, setWalletToRemove] = useState(null);
|
|
30719
30758
|
const [copiedAddress, setCopiedAddress] = useState(null);
|
|
30759
|
+
const [renamingAddress, setRenamingAddress] = useState(null);
|
|
30760
|
+
const [renameValue, setRenameValue] = useState("");
|
|
30761
|
+
const [labelError, setLabelError] = useState(null);
|
|
30762
|
+
const [setDefaultError, setSetDefaultError] = useState(null);
|
|
30720
30763
|
const copyTimeoutRef = useRef(void 0);
|
|
30721
30764
|
useEffect(() => () => clearTimeout(copyTimeoutRef.current), []);
|
|
30722
|
-
|
|
30765
|
+
useEffect(() => {
|
|
30766
|
+
if (readOnly) setRenamingAddress(null);
|
|
30767
|
+
}, [readOnly]);
|
|
30768
|
+
const copyAddress = useCallback(async (address) => {
|
|
30723
30769
|
try {
|
|
30724
30770
|
await navigator.clipboard.writeText(address);
|
|
30725
30771
|
clearTimeout(copyTimeoutRef.current);
|
|
@@ -30727,9 +30773,27 @@ function WalletList({
|
|
|
30727
30773
|
copyTimeoutRef.current = setTimeout(() => setCopiedAddress(null), 2e3);
|
|
30728
30774
|
} catch {
|
|
30729
30775
|
}
|
|
30730
|
-
};
|
|
30776
|
+
}, []);
|
|
30731
30777
|
const canAdd = !readOnly && !!onAdd;
|
|
30732
30778
|
const canRemove = !readOnly && !!onRemove;
|
|
30779
|
+
const canSetDefault = !readOnly && !!onSetDefault;
|
|
30780
|
+
const canLabel = !readOnly && !!onLabel;
|
|
30781
|
+
const canConnect = !readOnly && !!onConnect;
|
|
30782
|
+
const getSafeExplorerUrl = useCallback(
|
|
30783
|
+
(address) => {
|
|
30784
|
+
if (!getExplorerUrl) return null;
|
|
30785
|
+
try {
|
|
30786
|
+
const url = getExplorerUrl(address);
|
|
30787
|
+
if (!url) return null;
|
|
30788
|
+
const parsed = new URL(url);
|
|
30789
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
30790
|
+
return parsed.toString();
|
|
30791
|
+
} catch {
|
|
30792
|
+
return null;
|
|
30793
|
+
}
|
|
30794
|
+
},
|
|
30795
|
+
[getExplorerUrl]
|
|
30796
|
+
);
|
|
30733
30797
|
const handleAdd = async () => {
|
|
30734
30798
|
const trimmed = newAddress.trim();
|
|
30735
30799
|
const error2 = validateEthereumAddress(trimmed);
|
|
@@ -30757,8 +30821,191 @@ function WalletList({
|
|
|
30757
30821
|
setRemoveError("Failed to remove wallet. Please try again.");
|
|
30758
30822
|
}
|
|
30759
30823
|
};
|
|
30760
|
-
|
|
30761
|
-
|
|
30824
|
+
const handleSetDefault = async (address) => {
|
|
30825
|
+
setSetDefaultError(null);
|
|
30826
|
+
try {
|
|
30827
|
+
await onSetDefault?.(address);
|
|
30828
|
+
} catch {
|
|
30829
|
+
setSetDefaultError("Failed to set default wallet. Please try again.");
|
|
30830
|
+
}
|
|
30831
|
+
};
|
|
30832
|
+
const handleLabelSave = async (address) => {
|
|
30833
|
+
setLabelError(null);
|
|
30834
|
+
try {
|
|
30835
|
+
await onLabel?.(address, renameValue.trim() || null);
|
|
30836
|
+
setRenamingAddress((current) => current === address ? null : current);
|
|
30837
|
+
} catch {
|
|
30838
|
+
setLabelError("Failed to update label. Please try again.");
|
|
30839
|
+
}
|
|
30840
|
+
};
|
|
30841
|
+
const hasWallets = wallets.length > 0;
|
|
30842
|
+
if (!hasWallets && !showAddForm && !canConnect) {
|
|
30843
|
+
return /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
|
|
30844
|
+
/* @__PURE__ */ jsx(
|
|
30845
|
+
EmptyState,
|
|
30846
|
+
{
|
|
30847
|
+
icon: emptyIcon,
|
|
30848
|
+
title: "No wallets connected",
|
|
30849
|
+
description: "Add a wallet address to receive equity on-chain.",
|
|
30850
|
+
actionLabel: canAdd ? "Add Wallet" : void 0,
|
|
30851
|
+
onAction: canAdd ? () => setShowAddForm(true) : void 0
|
|
30852
|
+
}
|
|
30853
|
+
),
|
|
30854
|
+
children
|
|
30855
|
+
] });
|
|
30856
|
+
}
|
|
30857
|
+
return /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
|
|
30858
|
+
wallets.map((w) => {
|
|
30859
|
+
const normalizedWalletAddress = normalizeWalletAddress(w.address);
|
|
30860
|
+
const setDefaultActionLoading = setDefaultLoading && (!setDefaultAddress || normalizeWalletAddress(setDefaultAddress) === normalizedWalletAddress);
|
|
30861
|
+
const labelActionLoading = labelLoading && (!labelAddress || normalizeWalletAddress(labelAddress) === normalizedWalletAddress);
|
|
30862
|
+
const explorerUrl = getSafeExplorerUrl(w.address);
|
|
30863
|
+
return /* @__PURE__ */ jsxs(Stack, { gap: 0, children: [
|
|
30864
|
+
/* @__PURE__ */ jsxs(
|
|
30865
|
+
Group,
|
|
30866
|
+
{
|
|
30867
|
+
justify: "space-between",
|
|
30868
|
+
p: "xs",
|
|
30869
|
+
style: {
|
|
30870
|
+
borderRadius: radii.sm,
|
|
30871
|
+
border: `1px solid ${neutralColors[200]}`
|
|
30872
|
+
},
|
|
30873
|
+
children: [
|
|
30874
|
+
/* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
30875
|
+
/* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", children: getWalletLabel(w.type, typeLabels) }),
|
|
30876
|
+
w.label && /* @__PURE__ */ jsx(Text, { size: "xs", c: fairmintVars.colorTextSecondary, children: w.label }),
|
|
30877
|
+
w.defaultRecipient && /* @__PURE__ */ jsx(Badge, { size: "xs", color: colors.success, variant: "light", children: "Default" }),
|
|
30878
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", children: truncateAddress(w.address) })
|
|
30879
|
+
] }),
|
|
30880
|
+
/* @__PURE__ */ jsxs(Group, { gap: 4, children: [
|
|
30881
|
+
copyIcon && /* @__PURE__ */ jsx(Tooltip, { label: copiedAddress === w.address ? "Copied!" : "Copy address", children: /* @__PURE__ */ jsx(
|
|
30882
|
+
ActionIcon,
|
|
30883
|
+
{
|
|
30884
|
+
variant: "subtle",
|
|
30885
|
+
size: "sm",
|
|
30886
|
+
onClick: () => copyAddress(w.address),
|
|
30887
|
+
"aria-label": "Copy wallet address",
|
|
30888
|
+
children: copiedAddress === w.address ? copiedIcon ?? copyIcon : copyIcon
|
|
30889
|
+
}
|
|
30890
|
+
) }),
|
|
30891
|
+
canSetDefault && defaultIcon && !w.defaultRecipient && /* @__PURE__ */ jsx(Tooltip, { label: "Set as default recipient", children: /* @__PURE__ */ jsx(
|
|
30892
|
+
ActionIcon,
|
|
30893
|
+
{
|
|
30894
|
+
variant: "subtle",
|
|
30895
|
+
size: "sm",
|
|
30896
|
+
onClick: () => handleSetDefault(w.address),
|
|
30897
|
+
loading: setDefaultActionLoading,
|
|
30898
|
+
disabled: setDefaultActionLoading,
|
|
30899
|
+
"aria-label": "Set as default wallet",
|
|
30900
|
+
children: defaultIcon
|
|
30901
|
+
}
|
|
30902
|
+
) }),
|
|
30903
|
+
canLabel && renameIcon && /* @__PURE__ */ jsx(
|
|
30904
|
+
Tooltip,
|
|
30905
|
+
{
|
|
30906
|
+
label: renamingAddress === w.address ? "Cancel rename" : "Rename wallet",
|
|
30907
|
+
children: /* @__PURE__ */ jsx(
|
|
30908
|
+
ActionIcon,
|
|
30909
|
+
{
|
|
30910
|
+
variant: "subtle",
|
|
30911
|
+
size: "sm",
|
|
30912
|
+
onClick: () => {
|
|
30913
|
+
setLabelError(null);
|
|
30914
|
+
if (renamingAddress === w.address) {
|
|
30915
|
+
setRenamingAddress(null);
|
|
30916
|
+
} else {
|
|
30917
|
+
setRenamingAddress(w.address);
|
|
30918
|
+
setRenameValue(w.label ?? "");
|
|
30919
|
+
}
|
|
30920
|
+
},
|
|
30921
|
+
"aria-label": "Rename wallet",
|
|
30922
|
+
children: renameIcon
|
|
30923
|
+
}
|
|
30924
|
+
)
|
|
30925
|
+
}
|
|
30926
|
+
),
|
|
30927
|
+
explorerUrl && explorerIcon && /* @__PURE__ */ jsx(Tooltip, { label: "View on block explorer", children: /* @__PURE__ */ jsx(
|
|
30928
|
+
Anchor,
|
|
30929
|
+
{
|
|
30930
|
+
href: explorerUrl,
|
|
30931
|
+
target: "_blank",
|
|
30932
|
+
rel: "noopener noreferrer",
|
|
30933
|
+
"aria-label": "View on block explorer",
|
|
30934
|
+
c: colors.primary,
|
|
30935
|
+
style: {
|
|
30936
|
+
display: "inline-flex",
|
|
30937
|
+
alignItems: "center",
|
|
30938
|
+
justifyContent: "center",
|
|
30939
|
+
width: "1.625rem",
|
|
30940
|
+
height: "1.625rem",
|
|
30941
|
+
borderRadius: radii.sm
|
|
30942
|
+
},
|
|
30943
|
+
children: explorerIcon
|
|
30944
|
+
}
|
|
30945
|
+
) }),
|
|
30946
|
+
canRemove && removeIcon && (removableTypes ? removableTypes.some(
|
|
30947
|
+
(t) => normalizeWalletType(t) === normalizeWalletType(w.type)
|
|
30948
|
+
) : isRemovableWalletType(w.type)) && /* @__PURE__ */ jsx(Tooltip, { label: "Remove wallet", children: /* @__PURE__ */ jsx(
|
|
30949
|
+
ActionIcon,
|
|
30950
|
+
{
|
|
30951
|
+
variant: "subtle",
|
|
30952
|
+
size: "sm",
|
|
30953
|
+
color: colors.error,
|
|
30954
|
+
onClick: () => setWalletToRemove(w.address),
|
|
30955
|
+
disabled: removeLoading,
|
|
30956
|
+
"aria-label": "Remove wallet",
|
|
30957
|
+
children: removeIcon
|
|
30958
|
+
}
|
|
30959
|
+
) })
|
|
30960
|
+
] })
|
|
30961
|
+
]
|
|
30962
|
+
}
|
|
30963
|
+
),
|
|
30964
|
+
renamingAddress === w.address && /* @__PURE__ */ jsxs(Group, { gap: "xs", mt: "xs", align: "flex-start", children: [
|
|
30965
|
+
/* @__PURE__ */ jsx(
|
|
30966
|
+
TextInput,
|
|
30967
|
+
{
|
|
30968
|
+
value: renameValue,
|
|
30969
|
+
onChange: (e) => {
|
|
30970
|
+
setRenameValue(e.currentTarget.value);
|
|
30971
|
+
setLabelError(null);
|
|
30972
|
+
},
|
|
30973
|
+
placeholder: getWalletLabel(w.type, typeLabels),
|
|
30974
|
+
size: "xs",
|
|
30975
|
+
style: { flex: 1 },
|
|
30976
|
+
"aria-label": "Wallet label",
|
|
30977
|
+
maxLength: 50,
|
|
30978
|
+
error: labelError
|
|
30979
|
+
}
|
|
30980
|
+
),
|
|
30981
|
+
/* @__PURE__ */ jsx(
|
|
30982
|
+
Button,
|
|
30983
|
+
{
|
|
30984
|
+
size: "xs",
|
|
30985
|
+
loading: labelActionLoading,
|
|
30986
|
+
disabled: labelActionLoading,
|
|
30987
|
+
onClick: () => handleLabelSave(w.address),
|
|
30988
|
+
children: "Save"
|
|
30989
|
+
}
|
|
30990
|
+
),
|
|
30991
|
+
/* @__PURE__ */ jsx(
|
|
30992
|
+
Button,
|
|
30993
|
+
{
|
|
30994
|
+
size: "xs",
|
|
30995
|
+
variant: "subtle",
|
|
30996
|
+
color: colors.neutral,
|
|
30997
|
+
onClick: () => {
|
|
30998
|
+
setRenamingAddress(null);
|
|
30999
|
+
setLabelError(null);
|
|
31000
|
+
},
|
|
31001
|
+
children: "Cancel"
|
|
31002
|
+
}
|
|
31003
|
+
)
|
|
31004
|
+
] })
|
|
31005
|
+
] }, walletKey(w));
|
|
31006
|
+
}),
|
|
31007
|
+
setDefaultError && /* @__PURE__ */ jsx(Text, { size: "sm", c: colors.error, children: setDefaultError }),
|
|
31008
|
+
!hasWallets && !showAddForm && /* @__PURE__ */ jsx(
|
|
30762
31009
|
EmptyState,
|
|
30763
31010
|
{
|
|
30764
31011
|
icon: emptyIcon,
|
|
@@ -30767,52 +31014,19 @@ function WalletList({
|
|
|
30767
31014
|
actionLabel: canAdd ? "Add Wallet" : void 0,
|
|
30768
31015
|
onAction: canAdd ? () => setShowAddForm(true) : void 0
|
|
30769
31016
|
}
|
|
30770
|
-
)
|
|
30771
|
-
|
|
30772
|
-
|
|
30773
|
-
wallets.map((w) => /* @__PURE__ */ jsxs(
|
|
30774
|
-
Group,
|
|
31017
|
+
),
|
|
31018
|
+
canConnect && /* @__PURE__ */ jsx(
|
|
31019
|
+
Button,
|
|
30775
31020
|
{
|
|
30776
|
-
|
|
30777
|
-
|
|
30778
|
-
|
|
30779
|
-
|
|
30780
|
-
|
|
30781
|
-
|
|
30782
|
-
children:
|
|
30783
|
-
|
|
30784
|
-
|
|
30785
|
-
w.label && /* @__PURE__ */ jsx(Text, { size: "xs", c: fairmintVars.colorTextSecondary, children: w.label }),
|
|
30786
|
-
/* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", children: truncateAddress(w.address) })
|
|
30787
|
-
] }),
|
|
30788
|
-
/* @__PURE__ */ jsxs(Group, { gap: 4, children: [
|
|
30789
|
-
copyIcon && /* @__PURE__ */ jsx(Tooltip, { label: copiedAddress === w.address ? "Copied!" : "Copy address", children: /* @__PURE__ */ jsx(
|
|
30790
|
-
ActionIcon,
|
|
30791
|
-
{
|
|
30792
|
-
variant: "subtle",
|
|
30793
|
-
size: "sm",
|
|
30794
|
-
onClick: () => copyAddress(w.address),
|
|
30795
|
-
"aria-label": "Copy wallet address",
|
|
30796
|
-
children: copiedAddress === w.address ? copiedIcon ?? copyIcon : copyIcon
|
|
30797
|
-
}
|
|
30798
|
-
) }),
|
|
30799
|
-
canRemove && removeIcon && removableTypes.includes(w.type) && /* @__PURE__ */ jsx(Tooltip, { label: "Remove wallet", children: /* @__PURE__ */ jsx(
|
|
30800
|
-
ActionIcon,
|
|
30801
|
-
{
|
|
30802
|
-
variant: "subtle",
|
|
30803
|
-
size: "sm",
|
|
30804
|
-
color: colors.error,
|
|
30805
|
-
onClick: () => setWalletToRemove(w.address),
|
|
30806
|
-
disabled: removeLoading,
|
|
30807
|
-
"aria-label": "Remove wallet",
|
|
30808
|
-
children: removeIcon
|
|
30809
|
-
}
|
|
30810
|
-
) })
|
|
30811
|
-
] })
|
|
30812
|
-
]
|
|
30813
|
-
},
|
|
30814
|
-
w.address
|
|
30815
|
-
)),
|
|
31021
|
+
variant: "light",
|
|
31022
|
+
size: "xs",
|
|
31023
|
+
leftSection: connectIcon,
|
|
31024
|
+
onClick: onConnect,
|
|
31025
|
+
loading: connectLoading,
|
|
31026
|
+
mt: "xs",
|
|
31027
|
+
children: "Connect Wallet"
|
|
31028
|
+
}
|
|
31029
|
+
),
|
|
30816
31030
|
canAdd && (showAddForm ? /* @__PURE__ */ jsxs(Group, { gap: "xs", mt: "xs", children: [
|
|
30817
31031
|
/* @__PURE__ */ jsx(
|
|
30818
31032
|
TextInput,
|
|
@@ -30843,7 +31057,7 @@ function WalletList({
|
|
|
30843
31057
|
children: "Cancel"
|
|
30844
31058
|
}
|
|
30845
31059
|
)
|
|
30846
|
-
] }) : /* @__PURE__ */ jsx(
|
|
31060
|
+
] }) : hasWallets ? /* @__PURE__ */ jsx(
|
|
30847
31061
|
Button,
|
|
30848
31062
|
{
|
|
30849
31063
|
variant: "light",
|
|
@@ -30853,7 +31067,8 @@ function WalletList({
|
|
|
30853
31067
|
mt: "xs",
|
|
30854
31068
|
children: "Add Wallet"
|
|
30855
31069
|
}
|
|
30856
|
-
)),
|
|
31070
|
+
) : null),
|
|
31071
|
+
children,
|
|
30857
31072
|
/* @__PURE__ */ jsx(
|
|
30858
31073
|
ConfirmDialog,
|
|
30859
31074
|
{
|
|
@@ -31013,9 +31228,14 @@ export {
|
|
|
31013
31228
|
formatPhoneDisplay,
|
|
31014
31229
|
formatPreciseWithCurrency,
|
|
31015
31230
|
getAvatarColor,
|
|
31231
|
+
getWalletDisplayName,
|
|
31232
|
+
getWalletLabel,
|
|
31016
31233
|
isEthereumAddress,
|
|
31234
|
+
isRemovableWalletType,
|
|
31235
|
+
isSystemWalletType,
|
|
31017
31236
|
neutralColors,
|
|
31018
31237
|
normalizePhone,
|
|
31238
|
+
normalizeWalletType,
|
|
31019
31239
|
notify,
|
|
31020
31240
|
passwordSchema,
|
|
31021
31241
|
phoneSchema,
|
|
@@ -31038,6 +31258,7 @@ export {
|
|
|
31038
31258
|
useScrollIntoView,
|
|
31039
31259
|
useViewportSize,
|
|
31040
31260
|
validateEthereumAddress,
|
|
31261
|
+
walletKey,
|
|
31041
31262
|
z,
|
|
31042
31263
|
zipSchema
|
|
31043
31264
|
};
|