diff --git a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx
index 08b19ca04..dcbd4e397 100644
--- a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx
+++ b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx
@@ -8,7 +8,13 @@ import {
getProposalDataDocument,
getProposalDataQuery,
} from "#/subgraph/.graphclient";
-import { Badge, Button, DisplayNumber, EthAddress, Statistic } from "@/components";
+import {
+ Badge,
+ Button,
+ DisplayNumber,
+ EthAddress,
+ Statistic,
+} from "@/components";
import { ConvictionBarChart } from "@/components/Charts/ConvictionBarChart";
import { LoadingSpinner } from "@/components/LoadingSpinner";
import { usePubSubContext } from "@/contexts/pubsub.context";
@@ -80,9 +86,17 @@ export default function Page({
!!proposalData &&
(proposalStatus[proposalData.proposalStatus] === "executed" ||
proposalStatus[proposalData.proposalStatus] === "cancelled");
- logOnce("debug", { isProposalEnded, proposalStatus: proposalStatus[proposalData?.proposalStatus] });
+ logOnce("debug", {
+ isProposalEnded,
+ proposalStatus: proposalStatus[proposalData?.proposalStatus],
+ });
- const { currentConvictionPct, thresholdPct, totalSupportPct, updateConvictionLast } = useConvictionRead({
+ const {
+ currentConvictionPct,
+ thresholdPct,
+ totalSupportPct,
+ updateConvictionLast,
+ } = useConvictionRead({
proposalData,
tokenData: data?.tokenGarden,
});
@@ -125,7 +139,7 @@ export default function Page({
topic: "proposal",
type: "update",
function: "distribute",
- id:proposalId,
+ id: proposalId,
containerId: data?.cvproposal?.strategy?.id,
chainId,
});
@@ -171,8 +185,8 @@ export default function Page({
-
- {prettyTimestamp(proposalData?.createdAt ?? 0)}
+
+ Submitted: {prettyTimestamp(proposalData?.createdAt ?? 0)}
@@ -192,26 +206,27 @@ export default function Page({
/>
}>
-
+
>
)}
}>
-
+
- Metrics
- {/* TODO: need designs for this entire section */}
{status && proposalStatus[status] === "executed" ?
-
-
- Proposal passed and executed successfully
-
-
- : (
+
+ Proposal passed and executed successfully!
+
+ : <>
+ Metrics
- )}
+ >
+ }
- {proposalStatus[status] !== "executed" && !isSignalingType && ( writeDistribute?.({ args:[poolId, [data.cvproposal?.strategy.id], encodedDataProposalId(Number(proposalIdNumber))] })} disabled={currentConvictionPct < thresholdPct} tooltip="Proposal not executable">Execute )}
-
+ {proposalStatus[status] !== "executed" && !isSignalingType && (
+
+ writeDistribute?.({
+ args: [
+ poolId,
+ [data.cvproposal?.strategy.id],
+ encodedDataProposalId(Number(proposalIdNumber)),
+ ],
+ })
+ }
+ disabled={currentConvictionPct < thresholdPct}
+ tooltip="Proposal not executable"
+ >
+ Execute
+
+ )}
);
}
-
diff --git a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/page.tsx b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/page.tsx
index 27665e603..55380b91a 100644
--- a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/page.tsx
+++ b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/page.tsx
@@ -196,7 +196,6 @@ export default function Page({
communityAddress={communityAddress}
tokenGarden={tokenGarden}
chainId={chain}
- spendingLimitPct={spendingLimitPct}
/>
)}
-
Registration cost:
+
Registration stake:
diff --git a/apps/web/app/(app)/gardens/[chain]/[garden]/page.tsx b/apps/web/app/(app)/gardens/[chain]/[garden]/page.tsx
index 1fc184377..d5d950338 100644
--- a/apps/web/app/(app)/gardens/[chain]/[garden]/page.tsx
+++ b/apps/web/app/(app)/gardens/[chain]/[garden]/page.tsx
@@ -166,12 +166,12 @@ export default function Page({
{
- if (fetching) {
- return ;
- }
- if (tokenGardens?.length) {
- return (
- <>
- {tokenGardens.map((garden) => (
+ return fetching ?
+
+ : <>
+ {tokenGardens?.map((garden) => (
))}
- >
- );
- }
- return (
- No Gardens
- );
+ >;
}, [fetching, tokenGardens?.length]);
return (
-
-
-
-
-
-
-
-
-
- Explore and Join Gardens Ecosystems
-
-
- A place where you help shape digital economies
-
+ <>
+
+
+
+
+
+
+
+
+
+ Explore and Join Gardens Ecosystems
+
+
+ A place where you help shape digital economies
+
+
+
+
+
-
-
-
-
-
+
+
+
+ >
);
}
diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx
index eba7d0732..056276278 100644
--- a/apps/web/app/page.tsx
+++ b/apps/web/app/page.tsx
@@ -8,11 +8,10 @@ import {
ArrowPathIcon,
FingerPrintIcon,
LockClosedIcon,
- ArrowLongRightIcon,
Battery50Icon,
} from "@heroicons/react/24/outline";
import Image from "next/image";
-import { newLogo, commF } from "@/assets";
+import { newLogo, commF, HomeBanner } from "@/assets";
import { Button } from "@/components";
import { ChainIcon } from "@/configs/chainServer";
@@ -75,16 +74,6 @@ const Hero = () => {
))} */}
-
{
healthy, fun, intuitive, secure, and open.
- {/*
+
{
return (
-
-
+
+
Cultivate change with Gardens
-
- Join our Beta and start growing your community.
+
+ Join our pre-beta release and start growing your community.
{/* TODO: link to gardnes form */}
@@ -372,33 +367,15 @@ const SignUp = () => {
>
Launch App
-
-
-
-
-
-
-
-
-
-
+
diff --git a/apps/web/assets/Banner.png b/apps/web/assets/Banner.png
new file mode 100644
index 000000000..80ae08088
Binary files /dev/null and b/apps/web/assets/Banner.png differ
diff --git a/apps/web/assets/HomeBanner.png b/apps/web/assets/HomeBanner.png
new file mode 100644
index 000000000..7ebf7fef7
Binary files /dev/null and b/apps/web/assets/HomeBanner.png differ
diff --git a/apps/web/assets/TreeThree.svg b/apps/web/assets/TreeThree.svg
index ae9574da2..e4dd76ac6 100644
--- a/apps/web/assets/TreeThree.svg
+++ b/apps/web/assets/TreeThree.svg
@@ -1,22 +1,89 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/assets/TreeThree3.svg b/apps/web/assets/TreeThree3.svg
new file mode 100644
index 000000000..ae9574da2
--- /dev/null
+++ b/apps/web/assets/TreeThree3.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/assets/TreeTwo.svg b/apps/web/assets/TreeTwo.svg
index 9fc29db0c..4a77125e2 100644
--- a/apps/web/assets/TreeTwo.svg
+++ b/apps/web/assets/TreeTwo.svg
@@ -1,25 +1,32 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/apps/web/assets/TreeTwo2.svg b/apps/web/assets/TreeTwo2.svg
new file mode 100644
index 000000000..9fc29db0c
--- /dev/null
+++ b/apps/web/assets/TreeTwo2.svg
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/assets/WalletIcon.svg b/apps/web/assets/WalletIcon.svg
index 57c63212f..37e93dd49 100644
--- a/apps/web/assets/WalletIcon.svg
+++ b/apps/web/assets/WalletIcon.svg
@@ -1,29 +1,3 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/apps/web/assets/clouds1.svg b/apps/web/assets/clouds1.svg
index d2a603b89..46cdc3e0f 100644
--- a/apps/web/assets/clouds1.svg
+++ b/apps/web/assets/clouds1.svg
@@ -1,49 +1,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
diff --git a/apps/web/assets/clouds11.svg b/apps/web/assets/clouds11.svg
new file mode 100644
index 000000000..d2a603b89
--- /dev/null
+++ b/apps/web/assets/clouds11.svg
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/web/assets/clouds2.svg b/apps/web/assets/clouds2.svg
index 052d93598..42448498e 100644
--- a/apps/web/assets/clouds2.svg
+++ b/apps/web/assets/clouds2.svg
@@ -1,23 +1,8 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
diff --git a/apps/web/assets/clouds22.svg b/apps/web/assets/clouds22.svg
new file mode 100644
index 000000000..052d93598
--- /dev/null
+++ b/apps/web/assets/clouds22.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/web/assets/index.ts b/apps/web/assets/index.ts
index c340f952b..29973927e 100644
--- a/apps/web/assets/index.ts
+++ b/apps/web/assets/index.ts
@@ -25,3 +25,5 @@ export { default as TxError } from "./TxError.svg";
export { default as TxPreparing } from "./TxPreparing.svg";
export { default as TxInProgress } from "./TxInProgress.svg";
export { default as TxIdle } from "./TxIdle.svg";
+export { default as Banner } from "./Banner.png";
+export { default as HomeBanner } from "./HomeBanner.png";
diff --git a/apps/web/components/Breadcrumbs.tsx b/apps/web/components/Breadcrumbs.tsx
index fda199a4b..4b27a3a4c 100644
--- a/apps/web/components/Breadcrumbs.tsx
+++ b/apps/web/components/Breadcrumbs.tsx
@@ -1,9 +1,13 @@
"use client";
import React, { useEffect, useState } from "react";
-import { ChevronRightIcon } from "@heroicons/react/24/solid";
+import {
+ ChevronRightIcon,
+ ExclamationTriangleIcon,
+} from "@heroicons/react/24/solid";
import Link from "next/link";
import { usePathname } from "next/navigation";
+import { Button } from "./Button";
import { getTitlesFromUrlSegments } from "@/services/getTitlesFromUrlSegments";
interface Breadcrumb {
@@ -18,6 +22,15 @@ const truncateString = (str: string) => {
export function Breadcrumbs() {
const path = usePathname();
const [breadcrumbs, setBreadcrumbs] = useState([]);
+ const notAuditedDisclaimerAckStorageKey = "NotAuditedDisclaimerAck";
+ const [openDisclaimer, setOpenDisclaimer] = useState(false);
+
+ useEffect(() => {
+ const disclaimerAcknowledged = localStorage.getItem(
+ notAuditedDisclaimerAckStorageKey,
+ );
+ setOpenDisclaimer(disclaimerAcknowledged !== "true");
+ }, []);
const fetchBreadcrumbs = async (): Promise => {
const segments = path.split("/").filter((segment) => segment !== "");
@@ -53,6 +66,11 @@ export function Breadcrumbs() {
})();
}, [path]);
+ const handleDisclaimerAcknowledgment = () => {
+ setOpenDisclaimer(false);
+ localStorage.setItem(notAuditedDisclaimerAckStorageKey, "true");
+ };
+
if (!breadcrumbs.length) {
return <>>;
}
@@ -85,6 +103,32 @@ export function Breadcrumbs() {
))}
+ {openDisclaimer && (
+
+
+
+
+
Disclaimer
+
+
+ You are exploring the frontier with our contracts.{" "}
+
+ Please note that they have not been audited yet
+
+ . Exercise caution and proceed at your own risk.
+
+
+
+ I understand
+
+
+
+
+ )}
>
);
}
diff --git a/apps/web/components/Charts/ChartWrapper.tsx b/apps/web/components/Charts/ChartWrapper.tsx
index 75be28d00..4dbee2bad 100644
--- a/apps/web/components/Charts/ChartWrapper.tsx
+++ b/apps/web/components/Charts/ChartWrapper.tsx
@@ -28,12 +28,12 @@ export const ChartWrapper = ({
name: "Support",
// TODO: missing color in Design system: ask designer
className: "bg-[#A8E066] h-4 w-4 rounded-full",
- info: "Represents the pool weight allocated in favor of a proposal.",
+ info: "Represents the total pool voting weight currently allocated to a proposal.",
},
{
name: "Conviction",
className: "bg-primary-content h-4 w-4 rounded-full",
- info: "Accumulated allocation power for a proposal, increasing over time.",
+ info: "Accumulated pool voting weight for a proposal, increasing over time, based on the conviction growth rate.",
},
{
name: "Threshold",
@@ -59,8 +59,8 @@ export const ChartWrapper = ({
- :
}
- {item.name}
+ :
}
+ {item.name}
diff --git a/apps/web/components/Charts/ConvictionBarChart.tsx b/apps/web/components/Charts/ConvictionBarChart.tsx
index 290d9185b..51182f699 100644
--- a/apps/web/components/Charts/ConvictionBarChart.tsx
+++ b/apps/web/components/Charts/ConvictionBarChart.tsx
@@ -235,7 +235,8 @@ export const ConvictionBarChart = ({
trigger: "axis",
valueFormatter: (value) => value + "%",
borderWidth: 1,
- borderColor: "#191919",
+ borderColor: "#65AD18",
+ backgroundColor: "#FCFFF7",
axisPointer: {
type: "none",
},
@@ -248,9 +249,7 @@ export const ConvictionBarChart = ({
bottom: compact ? "0%" : "25%",
containLabel: false,
},
- // TODO: realted to re render in PoolId page (check)
- animation: false,
- //animationDurationUpdate: 1200,
+ animation: true,
barGap: "-100%",
series: [
{
@@ -261,7 +260,7 @@ export const ConvictionBarChart = ({
borderRadius: [20, 20, 20, 20],
},
showBackground: true,
- backgroundStyle:{
+ backgroundStyle: {
color: "#F0F0F0",
borderRadius: [20, 20, 20, 20],
},
diff --git a/apps/web/components/ConnectWalletButton.tsx b/apps/web/components/ConnectWalletButton.tsx
index 5853ecf44..34c474b91 100644
--- a/apps/web/components/ConnectWalletButton.tsx
+++ b/apps/web/components/ConnectWalletButton.tsx
@@ -15,7 +15,7 @@ import {
useSwitchNetwork,
} from "wagmi";
import { walletIcon } from "@/assets";
-import { Button } from "@/components";
+import { Button, DisplayNumber } from "@/components";
import { ChainIcon } from "@/configs/chainServer";
import { useChainFromPath } from "@/hooks/useChainFromPath";
import { formatAddress } from "@/utils/formatAddress";
@@ -63,8 +63,9 @@ export function ConnectWallet() {
alt="wallet"
height={20}
width={20}
+ loading="lazy"
/>
- Connect
+ Connect wallet
);
}
@@ -80,49 +81,49 @@ export function ConnectWallet() {
);
}
+
//Is CONNECTED to a supported chains with condition => urlChainId(urlChain) === chainId(wallet)
//Dropdown menu with wallet, balance, switch network and disconnect buttons
return (
-
+
{({ open }) => (
<>
-
+
{formatAddress(accountAddress.address)}
-
-
+
+
{(
!urlChainId ||
isNaN(urlChainId!) ||
chain.id === urlChainId
) ?
<>
-
Connected to
-
-
-
-
{chain.name}
+
+
{chain.name}
>
- :
- Network mismatch
-
+ :
+ Switch to network {chainFromPath?.name ?? ""}
+
}
-
-
+
+
{/* wallet and token balance info */}
-
Wallet {" "}
-
{wallet}
+
Wallet
{" "}
+
{wallet}
-
Balance
-
- {" "}
- {!tokenUrlAddress ?
- "Unknow garden"
- : Number(token?.formatted).toFixed(0)}{" "}
- {token?.symbol === "ETH" ? "" : token?.symbol}
-
+
Balance
+
+
@@ -177,7 +178,7 @@ export function ConnectWallet() {
disconnect()}
- btnStyle="outline"
+ btnStyle="filled"
color="danger"
className="w-full"
icon={
@@ -198,6 +199,17 @@ export function ConnectWallet() {
);
})()}
+ {urlChainId === chain?.id && tokenUrlAddress !== undefined && (
+
+ )}
>
);
}}
diff --git a/apps/web/components/IncreasePower.tsx b/apps/web/components/IncreasePower.tsx
index f191b0786..c0abddf39 100644
--- a/apps/web/components/IncreasePower.tsx
+++ b/apps/web/components/IncreasePower.tsx
@@ -1,6 +1,7 @@
"use client";
import { useEffect, useState } from "react";
+import { Dnum } from "dnum";
import { parseUnits } from "viem";
import { Address, useAccount, useBalance } from "wagmi";
import {
@@ -11,6 +12,7 @@ import {
import { Button } from "./Button";
import { DisplayNumber } from "./DisplayNumber";
import { InfoBox } from "./InfoBox";
+import { InfoIcon } from "./InfoIcon";
import { TransactionModal, TransactionProps } from "./TransactionModal";
import { usePubSubContext } from "@/contexts/pubsub.context";
import { useChainIdFromPath } from "@/hooks/useChainIdFromPath";
@@ -19,6 +21,7 @@ import { ConditionObject, useDisableButtons } from "@/hooks/useDisableButtons";
import { useHandleAllowance } from "@/hooks/useHandleAllowance";
import { registryCommunityABI } from "@/src/generated";
import { abiWithErrors2 } from "@/utils/abiWithErrors";
+import { parseToken } from "@/utils/numbers";
import { getTxMessage } from "@/utils/transactionMessages";
type IncreasePowerProps = {
@@ -34,12 +37,14 @@ type IncreasePowerProps = {
| "registerToken"
>;
tokenGarden: Pick;
+ registrationAmount: Dnum;
};
export const IncreasePower = ({
memberData,
registryCommunity,
tokenGarden,
+ registrationAmount,
}: IncreasePowerProps) => {
const {
symbol: tokenSymbol,
@@ -207,8 +212,14 @@ export const IncreasePower = ({
if (!isMember) return null;
+ const AddedStake = [
+ BigInt(memberStakedTokens - registerStakeAmountBigInt),
+ tokenDecimals,
+ ] as Dnum;
+
return (
-
+
+ Your stake
-
-
-
-
+
-
-
Added Stake:
-
+
Total Staked in the community:
+
+
+
+
diff --git a/apps/web/components/NavBar.tsx b/apps/web/components/NavBar.tsx
index d7145b047..217b62f4e 100644
--- a/apps/web/components/NavBar.tsx
+++ b/apps/web/components/NavBar.tsx
@@ -13,15 +13,18 @@ export function NavBar() {
return (
{({ open }) => (
<>
-
-
+
+
-
-
+
+
- {/*
*/}
-
Gardens
+
Gardens
- {/* TODO: change or remove after alpha */}
-
- alpha version
-
+
+ pre-beta release{" "}
+
{/* {navItems.map(({ name, href }) => (
diff --git a/apps/web/components/PoolCard.tsx b/apps/web/components/PoolCard.tsx
index 2bb147b81..034959452 100644
--- a/apps/web/components/PoolCard.tsx
+++ b/apps/web/components/PoolCard.tsx
@@ -58,24 +58,17 @@ export function PoolCard({ pool, tokenGarden }: Props) {
label="proposals"
/>
{poolType && poolTypes[poolType] === "funding" && (
- }
-
- label="funds available" >
+ } label="funds available">
-
-
)}
{!isEnabled ?
-
+
Waiting for approval
diff --git a/apps/web/components/PoolGovernance.tsx b/apps/web/components/PoolGovernance.tsx
index 909f8c875..154ddc3a6 100644
--- a/apps/web/components/PoolGovernance.tsx
+++ b/apps/web/components/PoolGovernance.tsx
@@ -8,6 +8,7 @@ import {
Badge,
DisplayNumber,
CheckPassport,
+ InfoBox,
} from "@/components/";
import { LightCVStrategy } from "@/types";
@@ -32,62 +33,63 @@ export const PoolGovernance: React.FC
= ({
}) => {
const showPoolGovernanceData = isMemberCommunity && memberActivatedStrategy;
+ const poolSystem = strategy.config.pointSystem;
+
+ const poolSystemDefinition: { [key: number]: string } = {
+ 0: "This pool has a fixed points system, meaning every member has the same governance weight, limited to their registration stake.",
+ 1: "This pool has a capped points system, meaning your governance weight will increase but capped based to maximum of tokens you have staked.",
+ 2: "This pool has an unlimited points system, allowing you to increase your governance weight without restrictions as you stake more tokens.",
+ 3: "This pool has a quadratic points system, meaning your governance weight grows at a squared rate relative to the tokens you have staked.",
+ };
+
return (
-
+
-
-
-
-
- {showPoolGovernanceData ?
- <>
-
-
Total staked in community:
-
-
-
-
-
Your governance weight:
-
- {memberPoolWeight.toFixed(2)} %
- of the pool
-
-
- >
- :
- }
-
-
-
-
-
+
+
+
+
Your stake in the community:
+
-
+
+
+ {showPoolGovernanceData && (
+
+
+
Your governance weight:
+
+ {memberPoolWeight.toFixed(2)} %
+
+
+
+
+
+ )}
diff --git a/apps/web/components/PoolMetrics.tsx b/apps/web/components/PoolMetrics.tsx
index d84f2c5cf..6b0211ad2 100644
--- a/apps/web/components/PoolMetrics.tsx
+++ b/apps/web/components/PoolMetrics.tsx
@@ -14,14 +14,13 @@ import { useDisableButtons } from "@/hooks/useDisableButtons";
import { useHandleAllowance } from "@/hooks/useHandleAllowance";
import { alloABI } from "@/src/generated";
import { abiWithErrors } from "@/utils/abiWithErrors";
-import { formatTokenAmount, MAX_RATIO_CONSTANT } from "@/utils/numbers";
+import { formatTokenAmount } from "@/utils/numbers";
import { getTxMessage } from "@/utils/transactionMessages";
interface PoolMetricsProps {
poolAmount: number;
communityAddress: Address;
tokenGarden: Pick
;
- spendingLimitPct: number;
alloInfo: Allo;
poolId: number;
chainId: string;
@@ -32,7 +31,6 @@ export const PoolMetrics: FC = ({
poolAmount,
communityAddress,
tokenGarden,
- spendingLimitPct,
poolId,
chainId,
}) => {
@@ -116,28 +114,20 @@ export const PoolMetrics: FC = ({
-
-
-
-
-
-
Funds Available:
-
- {formatTokenAmount(poolAmount, tokenGarden.decimals)}{" "}
- {tokenGarden.symbol}
-
-
-
-
Spending Limit:
-
- {`${(spendingLimitPct * MAX_RATIO_CONSTANT).toFixed(2)} %`}
-
-
+