[]
+}
+
+export default function ProposalSignatories(props: Props) {
+ return (
+
+
+ Signatories - {props.proposal.account.signatoriesCount} /{' '}
+ {props.proposal.account.signatoriesSignedOffCount}
+
+
+
+ )
+}
diff --git a/components/ProposalTopVotersBubbleChart.tsx b/components/ProposalTopVotersBubbleChart.tsx
new file mode 100644
index 0000000000..c8fe019b93
--- /dev/null
+++ b/components/ProposalTopVotersBubbleChart.tsx
@@ -0,0 +1,152 @@
+import { useEffect, useRef, useState } from 'react'
+import AutoSizer from 'react-virtualized-auto-sizer'
+import type { HierarchyCircularNode } from 'd3'
+
+import { VoterDisplayData, VoteType } from '@models/proposal'
+import { abbreviateAddress } from '@utils/formatting'
+import { getExplorerUrl } from '@components/explorer/tools'
+
+const voteTypeDomain = (type: VoteType) => {
+ switch (type) {
+ case VoteType.No:
+ return 'Nay'
+ case VoteType.Undecided:
+ return 'Undecided'
+ case VoteType.Yes:
+ return 'Yay'
+ }
+}
+
+const loadD3 = () => import('d3')
+
+type Unpromise = P extends Promise ? T : never
+type D3 = Unpromise>
+
+interface Props {
+ className?: string
+ data: VoterDisplayData[]
+ endpoint: string
+ height: number
+ maxNumBubbles: number
+ highlighted?: string
+ width: number
+ onHighlight?(key?: string): void
+}
+
+function Content(props: Props) {
+ const container = useRef(null)
+ const [d3, setD3] = useState(null)
+
+ useEffect(() => {
+ loadD3().then(setD3)
+ }, [])
+
+ useEffect(() => {
+ if (container.current && d3 && props.data.length) {
+ container.current.innerHTML = ''
+
+ const color = d3
+ .scaleOrdinal()
+ .domain([
+ voteTypeDomain(VoteType.Undecided),
+ voteTypeDomain(VoteType.Yes),
+ voteTypeDomain(VoteType.No),
+ ])
+ .range(['rgb(82, 82, 82)', 'rgb(101, 163, 13)', 'rgb(159, 18, 57)'])
+
+ const hierarchy = d3
+ .hierarchy({ children: props.data })
+ .sum((d: any) => (d.votesCast ? d.votesCast.toNumber() : 0))
+ .sort((a, b) => (b.value || 0) - (a.value || 0))
+
+ const pack = d3.pack().size([props.width, props.height]).padding(3)
+
+ const root = pack(hierarchy)
+
+ const parent = d3
+ .select(container.current)
+ .append('svg')
+ .attr('viewBox', [0, 0, props.width, props.height])
+ .attr('height', props.height)
+ .attr('width', props.width)
+ .attr('font-size', 10)
+ .attr('font-family', 'sans-serif')
+ .attr('text-anchor', 'middle')
+
+ const data = root
+ .descendants()
+ .slice(
+ 1,
+ props.maxNumBubbles
+ ) as HierarchyCircularNode[]
+
+ const group = parent
+ .selectAll('g')
+ .data(data)
+ .join('g')
+ .attr('transform', (d) => `translate(${d.x + 1},${d.y + 1})`)
+ .style('opacity', (d) => (d.data.key === props.highlighted ? 1 : 0.5))
+ .style('cursor', 'pointer')
+ .on('mouseenter', function () {
+ const node = d3
+ .select(this)
+ .datum() as HierarchyCircularNode
+ props.onHighlight?.(node.data.key)
+ })
+ .on('mouseleave', () => {
+ props.onHighlight?.()
+ })
+ .on('click', function () {
+ const node = d3
+ .select(this)
+ .datum() as HierarchyCircularNode
+
+ window.open(getExplorerUrl(props.endpoint, node.data.name), '_blank')
+ })
+
+ // draw circles
+ group
+ .append('circle')
+ .attr('r', (d) => d.r)
+ .attr('fill', (d) => color(voteTypeDomain(d.data.voteType)) as string)
+
+ // add labels
+ group
+ .append('svg:text')
+ .attr('fill', 'white')
+ .style('pointer-events', 'none')
+ .style('opacity', (d) => (d.data.key === props.highlighted ? 1 : 0.2))
+ .style('transform', (d) =>
+ d.data.key === props.highlighted ? 'scale(1.5)' : 'scale(1)'
+ )
+ .attr('y', '0.5em')
+ .text((d) => abbreviateAddress(d.data.name))
+ }
+ }, [
+ container,
+ props.data,
+ props.maxNumBubbles,
+ d3,
+ props.height,
+ props.width,
+ props.highlighted,
+ ])
+
+ return (
+
+ )
+}
+
+export default function ProposalTopVotersBubbleChart(
+ props: Omit
+) {
+ return (
+
+ )
+}
+
+ProposalTopVotersBubbleChart.defaultProps = {
+ maxNumBubbles: 50,
+}
diff --git a/components/ProposalTopVotersList.tsx b/components/ProposalTopVotersList.tsx
new file mode 100644
index 0000000000..e5d4a18144
--- /dev/null
+++ b/components/ProposalTopVotersList.tsx
@@ -0,0 +1,251 @@
+import { FixedSizeList } from 'react-window'
+import AutoSizer from 'react-virtualized-auto-sizer'
+import classNames from 'classnames'
+import BN from 'bn.js'
+import { BigNumber } from 'bignumber.js'
+import { useEffect, useMemo, useRef, useState } from 'react'
+
+import { formatPercentage } from '@utils/formatPercentage'
+import { VoterDisplayData, VoteType } from '@models/proposal'
+import { abbreviateAddress } from '@utils/formatting'
+import { getExplorerUrl } from '@components/explorer/tools'
+
+const ROW_STYLES =
+ 'absolute top-0 bottom-0 text-ellipsis overflow-hidden leading-[35px] px-2'
+
+const COL_1_STYLES = classNames(ROW_STYLES, 'left-0', 'w-[25%]')
+
+const COL_2_STYLES = classNames(
+ ROW_STYLES,
+ 'left-[30%]',
+ 'w-[15%]',
+ 'text-right'
+)
+
+const COL_3_STYLES = classNames(
+ ROW_STYLES,
+ 'left-[45%]',
+ 'w-[30%]',
+ 'text-right'
+)
+
+const COL_4_STYLES = classNames(
+ ROW_STYLES,
+ 'left-[75%]',
+ 'right-0',
+ 'text-right'
+)
+
+const formatNumber = (value: BN, decimals: number) => {
+ const num = new BigNumber(value.toString()).shiftedBy(-decimals)
+
+ if (typeof Intl === 'undefined' || typeof navigator === 'undefined') {
+ return num.toFormat()
+ }
+
+ const formatter = new Intl.NumberFormat(navigator.language, {
+ minimumFractionDigits: decimals,
+ })
+ return formatter.format(num.toNumber())
+}
+
+const voteTypeText = (type: VoteType) => {
+ switch (type) {
+ case VoteType.No:
+ return 'Nay'
+ case VoteType.Undecided:
+ return ''
+ case VoteType.Yes:
+ return 'Yay'
+ }
+}
+
+const Filter = ({
+ defaultChecked,
+ label,
+ onChange,
+}: {
+ defaultChecked?: boolean
+ label: string
+ onChange?(value: boolean): void
+}) => {
+ return (
+
+ )
+}
+
+const voteTypeBg = (type: VoteType) => {
+ switch (type) {
+ case VoteType.No:
+ return 'bg-rose-800'
+ case VoteType.Undecided:
+ return 'bg-neutral-600'
+ case VoteType.Yes:
+ return 'bg-lime-800'
+ }
+}
+
+interface Props {
+ className?: string
+ data: VoterDisplayData[]
+ endpoint: string
+ highlighted?: string
+ onHighlight?(key?: string): void
+}
+
+export default function ProposalTopVotersList(props: Props) {
+ const ref = useRef>(null)
+ const [showYays, setShowYays] = useState(true)
+ const [showNays, setShowNays] = useState(true)
+ const [showUndecideds, setShowUndecideds] = useState(true)
+
+ const records = useMemo(
+ () =>
+ props.data.filter((data) => {
+ if (data.voteType === VoteType.No && !showNays) {
+ return false
+ }
+
+ if (data.voteType === VoteType.Undecided && !showUndecideds) {
+ return false
+ }
+
+ if (data.voteType === VoteType.Yes && !showYays) {
+ return false
+ }
+
+ return true
+ }),
+ [props.data, showYays, showNays, showUndecideds]
+ )
+
+ useEffect(() => {
+ if (ref.current && props.highlighted) {
+ const index = records.findIndex((data) => data.key === props.highlighted)
+
+ if (index >= 0) {
+ ref.current.scrollToItem(index, 'smart')
+ }
+ }
+ }, [ref, props.highlighted, records])
+
+ return (
+
+
+
Account
+
Vote
+
Vote Weight
+
Percentage
+
+
+
+ Show:
+
+
+
+
+
+ )
+}
diff --git a/components/ProposalVoteResults.tsx b/components/ProposalVoteResults.tsx
new file mode 100644
index 0000000000..df2218b573
--- /dev/null
+++ b/components/ProposalVoteResults.tsx
@@ -0,0 +1,170 @@
+import { Governance, ProgramAccount, Proposal } from '@solana/spl-governance'
+import classNames from 'classnames'
+
+import { VoterDisplayData, VoteType } from '@models/proposal'
+import { formatPercentage } from '@utils/formatPercentage'
+
+interface Props {
+ className?: string
+ data: VoterDisplayData[]
+ governance: ProgramAccount
+ proposal: ProgramAccount
+}
+
+export default function ProposalVoteResult(props: Props) {
+ const yesPercent = props.data.reduce((acc, cur) => {
+ if (cur.voteType === VoteType.Yes) {
+ return acc + cur.votePercentage
+ }
+
+ return acc
+ }, 0)
+
+ const noPercent = props.data.reduce((acc, cur) => {
+ if (cur.voteType === VoteType.No) {
+ return acc + cur.votePercentage
+ }
+
+ return acc
+ }, 0)
+
+ const threshold =
+ props.proposal.account.voteThresholdPercentage?.value ||
+ props.governance.account.config.voteThresholdPercentage.value
+
+ return (
+
+
Vote Result
+
+
+
+
+
+
Yay
+
+ {formatPercentage(yesPercent)}
+
+
+
+
Nay
+
+ {formatPercentage(noPercent)}
+
+
+ {threshold && (
+ <>
+
+
+
Threshold
+
+ {formatPercentage(threshold)}
+
+
+ >
+ )}
+
+
+
+ )
+}
diff --git a/hooks/useSignatories.ts b/hooks/useSignatories.ts
new file mode 100644
index 0000000000..594db98f2f
--- /dev/null
+++ b/hooks/useSignatories.ts
@@ -0,0 +1,48 @@
+import { useEffect, useState } from 'react'
+import { pipe } from 'fp-ts/function'
+import { matchW } from 'fp-ts/TaskEither'
+import {
+ Proposal,
+ ProgramAccount,
+ RpcContext,
+ SignatoryRecord,
+} from '@solana/spl-governance'
+
+import useRpcContext from '@hooks/useRpcContext'
+import { getSignatories } from '@models/proposal'
+import useRealm from '@hooks/useRealm'
+import { fromOption } from 'fp-ts/Either'
+
+export default function useSignatories(proposal?: ProgramAccount) {
+ const { getRpcContext } = useRpcContext()
+ const [signatories, setSignatories] = useState<
+ ProgramAccount[]
+ >([])
+ const [context, setContext] = useState(null)
+ const { realm } = useRealm()
+
+ useEffect(() => {
+ if (realm) {
+ setContext(getRpcContext())
+ }
+ }, [realm])
+
+ useEffect(() => {
+ if (context && proposal) {
+ pipe(
+ () =>
+ getSignatories({
+ connection: context.connection,
+ programId: context.programId,
+ proposalPk: proposal.pubkey,
+ }).then(fromOption(() => new Error('Could not fetch signatories'))),
+ matchW((reason) => {
+ console.log(reason)
+ setSignatories([])
+ }, setSignatories)
+ )()
+ }
+ }, [context, proposal])
+
+ return signatories
+}
diff --git a/hooks/useVoteRecords.ts b/hooks/useVoteRecords.ts
new file mode 100644
index 0000000000..bb6baa1aa8
--- /dev/null
+++ b/hooks/useVoteRecords.ts
@@ -0,0 +1,90 @@
+import { useEffect, useMemo, useState } from 'react'
+import { pipe } from 'fp-ts/function'
+import { matchW, fromTaskOption } from 'fp-ts/TaskEither'
+import {
+ Proposal,
+ ProgramAccount,
+ VoteRecord,
+ TokenOwnerRecord,
+ RpcContext,
+} from '@solana/spl-governance'
+
+import useRpcContext from '@hooks/useRpcContext'
+import { getVoteRecords, getTokenOwnerRecords } from '@models/proposal'
+import useRealm from '@hooks/useRealm'
+import { buildTopVoters, VoteType } from '@models/proposal'
+
+export { VoteType }
+
+export default function useVoteRecords(proposal?: ProgramAccount) {
+ const { getRpcContext } = useRpcContext()
+ const [voteRecords, setVoteRecords] = useState[]>(
+ []
+ )
+ const [tokenOwnerRecords, setTokenOwnerRecords] = useState<
+ ProgramAccount[]
+ >([])
+ const [context, setContext] = useState(null)
+ const { mint, realm } = useRealm()
+
+ const governingTokenMintPk = proposal?.account.isVoteFinalized()
+ ? undefined
+ : proposal?.account.governingTokenMint
+
+ useEffect(() => {
+ if (context && proposal && realm) {
+ // fetch vote records
+ pipe(
+ () =>
+ getVoteRecords({
+ connection: context.connection,
+ programId: context.programId,
+ proposalPk: proposal.pubkey,
+ }),
+ fromTaskOption(() => new Error('Could not fetch vote records')),
+ matchW((reason) => {
+ console.log(reason)
+ setVoteRecords([])
+ }, setVoteRecords)
+ )()
+
+ // fetch token records
+ pipe(
+ () =>
+ getTokenOwnerRecords({
+ governingTokenMint: governingTokenMintPk,
+ connection: context.connection,
+ programId: context.programId,
+ realm: realm.pubkey,
+ }),
+ fromTaskOption(() => new Error('Could not fetch token records')),
+ matchW((reason) => {
+ console.log(reason)
+ setTokenOwnerRecords([])
+ }, setTokenOwnerRecords)
+ )()
+ }
+ }, [context, governingTokenMintPk, proposal, realm])
+
+ useEffect(() => {
+ if (realm) {
+ setContext(getRpcContext())
+ }
+ }, [realm])
+
+ const topVoters = useMemo(() => {
+ if (realm && proposal && mint) {
+ return buildTopVoters(
+ voteRecords,
+ tokenOwnerRecords,
+ realm,
+ proposal,
+ mint
+ )
+ }
+
+ return []
+ }, [voteRecords, tokenOwnerRecords, realm, proposal, mint])
+
+ return topVoters
+}
diff --git a/models/accounts/getAccountsByFilter.ts b/models/accounts/getAccountsByFilter.ts
new file mode 100644
index 0000000000..f9b17580cd
--- /dev/null
+++ b/models/accounts/getAccountsByFilter.ts
@@ -0,0 +1,49 @@
+import {
+ getGovernanceAccounts,
+ GovernanceAccount,
+ GovernanceAccountClass,
+ ProgramAccount,
+ MemcmpFilter,
+} from '@solana/spl-governance'
+import { Connection, PublicKey } from '@solana/web3.js'
+import { pipe } from 'fp-ts/function'
+import { tryCatch, map, match } from 'fp-ts/TaskEither'
+import { some, none } from 'fp-ts/Option'
+
+interface Args {
+ accountClass: GovernanceAccountClass
+ connection: Connection
+ filters: MemcmpFilter[]
+ programId: PublicKey
+}
+
+export function getAccountsByFilters({
+ accountClass,
+ connection,
+ filters,
+ programId,
+}: Args) {
+ return pipe(
+ tryCatch(
+ () =>
+ getGovernanceAccounts(
+ connection,
+ programId,
+ (accountClass as unknown) as new (args: any) => AccountType,
+ filters
+ ),
+ (error) =>
+ error instanceof Error ? error : new Error('Could not fetch accounts')
+ ),
+ map((accounts) =>
+ accounts.reduce((acc, account) => {
+ acc[account.pubkey.toBase58()] = account
+ return acc
+ }, {} as { [address: string]: ProgramAccount })
+ ),
+ match((error) => {
+ console.error(error)
+ return none
+ }, some)
+ )()
+}
diff --git a/models/accounts/index.ts b/models/accounts/index.ts
new file mode 100644
index 0000000000..a54d5a9fe8
--- /dev/null
+++ b/models/accounts/index.ts
@@ -0,0 +1 @@
+export * from './getAccountsByFilter'
diff --git a/models/proposal/buildTopVoters.ts b/models/proposal/buildTopVoters.ts
new file mode 100644
index 0000000000..b9cca91737
--- /dev/null
+++ b/models/proposal/buildTopVoters.ts
@@ -0,0 +1,107 @@
+import {
+ ProgramAccount,
+ VoteRecord,
+ TokenOwnerRecord,
+ Realm,
+ Proposal,
+} from '@solana/spl-governance'
+import { MintInfo } from '@solana/spl-token'
+import BN from 'bn.js'
+import { PublicKey } from '@solana/web3.js'
+import { BigNumber } from 'bignumber.js'
+
+import { calculateMaxVoteScore } from '@models/proposal/calulateMaxVoteScore'
+
+export enum VoteType {
+ No,
+ Undecided,
+ Yes,
+}
+
+export interface VoterDisplayData {
+ decimals: number
+ name: PublicKey
+ voteType: VoteType
+ votesCast: BN
+ votePercentage: number
+ key: string
+}
+
+const buildResults = (
+ key: PublicKey,
+ amount: BN,
+ label: VoteType,
+ total: BN,
+ decimals: number
+) => ({
+ decimals,
+ name: key,
+ voteType: label,
+ votesCast: amount,
+ key: key.toBase58(),
+ votePercentage: new BigNumber(amount.toString())
+ .shiftedBy(2)
+ .dividedBy(new BigNumber(total.toString()))
+ .toNumber(),
+})
+
+const ZERO = new BN(0)
+
+export function buildTopVoters(
+ voteRecords: ProgramAccount[],
+ tokenOwnerRecords: ProgramAccount[],
+ realm: ProgramAccount,
+ proposal: ProgramAccount,
+ governingTokenMint: MintInfo
+): VoterDisplayData[] {
+ const maxVote = calculateMaxVoteScore(realm, proposal, governingTokenMint)
+
+ const undecidedData = tokenOwnerRecords
+ .filter(
+ (tokenOwnerRecord) =>
+ !tokenOwnerRecord.account.governingTokenDepositAmount.isZero() &&
+ !voteRecords.some(
+ (voteRecord) =>
+ voteRecord.account.governingTokenOwner.toBase58() ===
+ tokenOwnerRecord.account.governingTokenOwner.toBase58()
+ )
+ )
+ .map((record) =>
+ buildResults(
+ record.account.governingTokenOwner,
+ record.account.governingTokenDepositAmount,
+ VoteType.Undecided,
+ maxVote,
+ governingTokenMint.decimals
+ )
+ )
+
+ const noVoteData = voteRecords
+ .filter((record) => record.account.getNoVoteWeight()?.gt(ZERO))
+ .map((record) =>
+ buildResults(
+ record.account.governingTokenOwner,
+ record.account.getNoVoteWeight()!,
+ VoteType.No,
+ maxVote,
+ governingTokenMint.decimals
+ )
+ )
+
+ const yesVoteData = voteRecords
+ .filter((record) => record.account.getYesVoteWeight()?.gt(ZERO))
+ .map((record) =>
+ buildResults(
+ record.account.governingTokenOwner,
+ record.account.getYesVoteWeight()!,
+ VoteType.Yes,
+ maxVote,
+ governingTokenMint.decimals
+ )
+ )
+
+ return undecidedData
+ .concat(yesVoteData)
+ .concat(noVoteData)
+ .sort((a, b) => b.votesCast.cmp(a.votesCast))
+}
diff --git a/models/proposal/calculateMintMaxVoteWeight.ts b/models/proposal/calculateMintMaxVoteWeight.ts
new file mode 100644
index 0000000000..2e4ebf406f
--- /dev/null
+++ b/models/proposal/calculateMintMaxVoteWeight.ts
@@ -0,0 +1,21 @@
+import { MintInfo } from '@solana/spl-token'
+import BN from 'bn.js'
+import { BigNumber } from 'bignumber.js'
+import { MintMaxVoteWeightSource } from '@solana/spl-governance'
+
+export function calculateMintMaxVoteWeight(
+ mint: MintInfo,
+ maxVoteWeightSource: MintMaxVoteWeightSource
+) {
+ if (maxVoteWeightSource.isFullSupply()) {
+ return mint.supply as BN
+ }
+
+ const supplyFraction = maxVoteWeightSource.getSupplyFraction()
+
+ const maxVoteWeight = new BigNumber(supplyFraction.toString())
+ .multipliedBy(mint.supply.toString())
+ .shiftedBy(-MintMaxVoteWeightSource.SUPPLY_FRACTION_DECIMALS)
+
+ return new BN(maxVoteWeight.dp(0, BigNumber.ROUND_DOWN).toString())
+}
diff --git a/models/proposal/calulateMaxVoteScore.ts b/models/proposal/calulateMaxVoteScore.ts
new file mode 100644
index 0000000000..77b04a1df0
--- /dev/null
+++ b/models/proposal/calulateMaxVoteScore.ts
@@ -0,0 +1,27 @@
+import { ProgramAccount, Realm, Proposal } from '@solana/spl-governance'
+import { MintInfo } from '@solana/spl-token'
+import BN from 'bn.js'
+
+import { calculateMintMaxVoteWeight } from '@models/proposal'
+
+export function calculateMaxVoteScore(
+ realm: ProgramAccount,
+ proposal: ProgramAccount,
+ governingTokenMint: MintInfo
+) {
+ if (proposal.account.isVoteFinalized() && proposal.account.maxVoteWeight) {
+ return proposal.account.maxVoteWeight
+ }
+
+ if (
+ proposal.account.governingTokenMint.toBase58() ===
+ realm.account.config.councilMint?.toBase58()
+ ) {
+ return governingTokenMint.supply as BN
+ }
+
+ return calculateMintMaxVoteWeight(
+ governingTokenMint,
+ realm.account.config.communityMintMaxVoteWeightSource
+ )
+}
diff --git a/models/proposal/getSignatories.ts b/models/proposal/getSignatories.ts
new file mode 100644
index 0000000000..c075fed7c4
--- /dev/null
+++ b/models/proposal/getSignatories.ts
@@ -0,0 +1,36 @@
+import { Connection, PublicKey } from '@solana/web3.js'
+import { pubkeyFilter, SignatoryRecord } from '@solana/spl-governance'
+import { none, map } from 'fp-ts/Option'
+import { pipe } from 'fp-ts/function'
+
+import { getAccountsByFilters } from '@models/accounts'
+
+interface Args {
+ connection: Connection
+ proposalPk: PublicKey
+ programId: PublicKey
+}
+
+export async function getSignatories({
+ connection,
+ programId,
+ proposalPk,
+}: Args) {
+ const filter = pubkeyFilter(1, proposalPk)
+
+ if (!filter) {
+ return none
+ }
+
+ const accounts = await getAccountsByFilters({
+ connection,
+ programId,
+ accountClass: SignatoryRecord,
+ filters: [filter],
+ })
+
+ return pipe(
+ accounts,
+ map((accounts) => Object.values(accounts))
+ )
+}
diff --git a/models/proposal/getTokenOwnerRecords.ts b/models/proposal/getTokenOwnerRecords.ts
new file mode 100644
index 0000000000..7791239e8c
--- /dev/null
+++ b/models/proposal/getTokenOwnerRecords.ts
@@ -0,0 +1,39 @@
+import { Connection, PublicKey } from '@solana/web3.js'
+import { pubkeyFilter, TokenOwnerRecord } from '@solana/spl-governance'
+import { none, map } from 'fp-ts/Option'
+import { pipe } from 'fp-ts/function'
+
+import { getAccountsByFilters } from '@models/accounts'
+
+interface Args {
+ connection: Connection
+ governingTokenMint?: PublicKey
+ programId: PublicKey
+ realm: PublicKey
+}
+
+export async function getTokenOwnerRecords({
+ connection,
+ governingTokenMint,
+ programId,
+ realm,
+}: Args) {
+ const filter1 = pubkeyFilter(1, realm)
+ const filter2 = pubkeyFilter(1 + 32, governingTokenMint)
+
+ if (!(filter1 && filter2)) {
+ return none
+ }
+
+ const accounts = await getAccountsByFilters({
+ connection,
+ programId,
+ accountClass: TokenOwnerRecord,
+ filters: [filter1, filter2],
+ })
+
+ return pipe(
+ accounts,
+ map((accounts) => Object.values(accounts))
+ )
+}
diff --git a/models/proposal/getVoteRecords.ts b/models/proposal/getVoteRecords.ts
new file mode 100644
index 0000000000..5aa7d737fc
--- /dev/null
+++ b/models/proposal/getVoteRecords.ts
@@ -0,0 +1,36 @@
+import { Connection, PublicKey } from '@solana/web3.js'
+import { pubkeyFilter, VoteRecord } from '@solana/spl-governance'
+import { none, map } from 'fp-ts/Option'
+import { pipe } from 'fp-ts/function'
+
+import { getAccountsByFilters } from '@models/accounts'
+
+interface Args {
+ connection: Connection
+ proposalPk: PublicKey
+ programId: PublicKey
+}
+
+export async function getVoteRecords({
+ connection,
+ programId,
+ proposalPk,
+}: Args) {
+ const filter = pubkeyFilter(1, proposalPk)
+
+ if (!filter) {
+ return none
+ }
+
+ const accounts = await getAccountsByFilters({
+ connection,
+ programId,
+ accountClass: VoteRecord,
+ filters: [filter],
+ })
+
+ return pipe(
+ accounts,
+ map((accounts) => Object.values(accounts))
+ )
+}
diff --git a/models/proposal/index.ts b/models/proposal/index.ts
new file mode 100644
index 0000000000..8990056623
--- /dev/null
+++ b/models/proposal/index.ts
@@ -0,0 +1,6 @@
+export * from './buildTopVoters'
+export * from './calculateMintMaxVoteWeight'
+export * from './calulateMaxVoteScore'
+export * from './getSignatories'
+export * from './getTokenOwnerRecords'
+export * from './getVoteRecords'
diff --git a/package.json b/package.json
index 14737dea91..252059ceaf 100644
--- a/package.json
+++ b/package.json
@@ -70,7 +70,9 @@
"bignumber.js": "^9.0.2",
"buffer-layout": "^1.2.2",
"classnames": "^2.3.1",
+ "d3": "^7.4.4",
"dayjs": "^1.11.1",
+ "fp-ts": "^2.12.1",
"goblingold-sdk": "^1.2.35",
"immer": "^9.0.12",
"next": "^12.1.5",
@@ -85,6 +87,8 @@
"react-hook-form": "^7.31.3",
"react-markdown": "^7.0.0",
"react-portal": "^4.2.2",
+ "react-virtualized-auto-sizer": "^1.0.6",
+ "react-window": "^1.8.7",
"remark-gfm": "^3.0.1",
"superstruct": "^0.15.4",
"ts-node": "^10.7.0",
@@ -96,6 +100,7 @@
"@notifi-network/notifi-core": "^0.12.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^11.2.5",
+ "@types/d3": "^7.4.0",
"@types/jest": "^27.4.1",
"@types/node": "^14.14.25",
"@types/react": "^17.0.44",
diff --git a/pages/dao/[symbol]/proposal/[pk]/explore.tsx b/pages/dao/[symbol]/proposal/[pk]/explore.tsx
new file mode 100644
index 0000000000..d20074da60
--- /dev/null
+++ b/pages/dao/[symbol]/proposal/[pk]/explore.tsx
@@ -0,0 +1,102 @@
+import { useState } from 'react'
+import { useRouter } from 'next/router'
+import classNames from 'classnames'
+import { ChevronLeftIcon } from '@heroicons/react/solid'
+
+import useProposal from '@hooks/useProposal'
+import useVoteRecords from '@hooks/useVoteRecords'
+import ProposalStateBadge from '@components/ProposalStatusBadge'
+import ProposalTopVotersList from '@components/ProposalTopVotersList'
+import ProposalTopVotersBubbleChart from '@components/ProposalTopVotersBubbleChart'
+import useWalletStore from 'stores/useWalletStore'
+import useSignatories from '@hooks/useSignatories'
+import ProposalSignatories from '@components/ProposalSignatories'
+import ProposalVoteResult from '@components/ProposalVoteResults'
+import ProposalRemainingVotingTime from '@components/ProposalRemainingVotingTime'
+
+export default function Explore() {
+ const { proposal, governance } = useProposal()
+ const [highlighted, setHighlighted] = useState()
+ const connection = useWalletStore((s) => s.connection)
+ const records = useVoteRecords(proposal)
+ const signatories = useSignatories(proposal)
+ const router = useRouter()
+
+ const endpoint = connection.endpoint
+
+ return (
+
+
+ {proposal && governance ? (
+
+
+
{proposal?.account.name}
+
+
+
Top Voters
+
setHighlighted(undefined)}
+ >
+
+
+
+
+
+ ) : (
+
+ )}
+
+ )
+}
diff --git a/pages/dao/[symbol]/proposal/[pk].tsx b/pages/dao/[symbol]/proposal/[pk]/index.tsx
similarity index 86%
rename from pages/dao/[symbol]/proposal/[pk].tsx
rename to pages/dao/[symbol]/proposal/[pk]/index.tsx
index bfd7774990..ec3a8a43d8 100644
--- a/pages/dao/[symbol]/proposal/[pk].tsx
+++ b/pages/dao/[symbol]/proposal/[pk]/index.tsx
@@ -20,9 +20,12 @@ import VoteResultStatus from '@components/VoteResultStatus'
import VoteResults from '@components/VoteResults'
import { resolveProposalDescription } from '@utils/helpers'
import PreviousRouteBtn from '@components/PreviousRouteBtn'
+import Link from 'next/link'
+import useQueryContext from '@hooks/useQueryContext'
+import { ChevronRightIcon } from '@heroicons/react/solid'
const Proposal = () => {
- const { realmInfo } = useRealm()
+ const { realmInfo, symbol } = useRealm()
const { proposal, descriptionLink } = useProposal()
const [description, setDescription] = useState('')
const { yesVoteProgress, yesVotesRequired } = useProposalVotes(
@@ -51,6 +54,9 @@ const Proposal = () => {
handleResolveDescription()
}
}, [descriptionLink])
+
+ const { fmtUrlWithCluster } = useQueryContext()
+
return (
@@ -140,6 +146,21 @@ const Proposal = () => {
)}
+ {proposal && (
+
+ )}
) : null}
diff --git a/utils/formatPercentage.ts b/utils/formatPercentage.ts
new file mode 100644
index 0000000000..f8685dc8ea
--- /dev/null
+++ b/utils/formatPercentage.ts
@@ -0,0 +1,11 @@
+export function formatPercentage(percentage: number) {
+ if (percentage === 0 || percentage === Infinity) {
+ return '0%'
+ }
+
+ if (percentage < 0.01) {
+ return '<0.01%'
+ }
+
+ return `${+percentage.toFixed(2)}%`
+}
diff --git a/utils/ntext.ts b/utils/ntext.ts
new file mode 100644
index 0000000000..c9dcd50690
--- /dev/null
+++ b/utils/ntext.ts
@@ -0,0 +1,7 @@
+export function ntext(count: number, singular: string, plural?: string) {
+ if (count === 1) {
+ return singular
+ }
+
+ return plural || `${singular}s`
+}
diff --git a/yarn.lock b/yarn.lock
index 74947117ad..7dcaa59072 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3245,6 +3245,216 @@
dependencies:
"@types/node" "*"
+"@types/d3-array@*":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.3.tgz#87d990bf504d14ad6b16766979d04e943c046dac"
+ integrity sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==
+
+"@types/d3-axis@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-3.0.1.tgz#6afc20744fa5cc0cbc3e2bd367b140a79ed3e7a8"
+ integrity sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-brush@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-3.0.1.tgz#ae5f17ce391935ca88b29000e60ee20452c6357c"
+ integrity sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-chord@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-3.0.1.tgz#54c8856c19c8e4ab36a53f73ba737de4768ad248"
+ integrity sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==
+
+"@types/d3-color@*":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.0.tgz#6594da178ded6c7c3842f3cc0ac84b156f12f2d4"
+ integrity sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==
+
+"@types/d3-contour@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-3.0.1.tgz#9ff4e2fd2a3910de9c5097270a7da8a6ef240017"
+ integrity sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==
+ dependencies:
+ "@types/d3-array" "*"
+ "@types/geojson" "*"
+
+"@types/d3-delaunay@*":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz#006b7bd838baec1511270cb900bf4fc377bbbf41"
+ integrity sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==
+
+"@types/d3-dispatch@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-3.0.1.tgz#a1b18ae5fa055a6734cb3bd3cbc6260ef19676e3"
+ integrity sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==
+
+"@types/d3-drag@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.1.tgz#fb1e3d5cceeee4d913caa59dedf55c94cb66e80f"
+ integrity sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-dsv@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-3.0.0.tgz#f3c61fb117bd493ec0e814856feb804a14cfc311"
+ integrity sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==
+
+"@types/d3-ease@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.0.tgz#c29926f8b596f9dadaeca062a32a45365681eae0"
+ integrity sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==
+
+"@types/d3-fetch@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-3.0.1.tgz#f9fa88b81aa2eea5814f11aec82ecfddbd0b8fe0"
+ integrity sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==
+ dependencies:
+ "@types/d3-dsv" "*"
+
+"@types/d3-force@*":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-3.0.3.tgz#76cb20d04ae798afede1ea6e41750763ff5a9c82"
+ integrity sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==
+
+"@types/d3-format@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-3.0.1.tgz#194f1317a499edd7e58766f96735bdc0216bb89d"
+ integrity sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==
+
+"@types/d3-geo@*":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-3.0.2.tgz#e7ec5f484c159b2c404c42d260e6d99d99f45d9a"
+ integrity sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==
+ dependencies:
+ "@types/geojson" "*"
+
+"@types/d3-hierarchy@*":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.0.tgz#4561bb7ace038f247e108295ef77b6a82193ac25"
+ integrity sha512-g+sey7qrCa3UbsQlMZZBOHROkFqx7KZKvUpRzI/tAp/8erZWpYq7FgNKvYwebi2LaEiVs1klhUfd3WCThxmmWQ==
+
+"@types/d3-interpolate@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz#e7d17fa4a5830ad56fe22ce3b4fac8541a9572dc"
+ integrity sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==
+ dependencies:
+ "@types/d3-color" "*"
+
+"@types/d3-path@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.0.0.tgz#939e3a784ae4f80b1fde8098b91af1776ff1312b"
+ integrity sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==
+
+"@types/d3-polygon@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-3.0.0.tgz#5200a3fa793d7736fa104285fa19b0dbc2424b93"
+ integrity sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==
+
+"@types/d3-quadtree@*":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz#433112a178eb7df123aab2ce11c67f51cafe8ff5"
+ integrity sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==
+
+"@types/d3-random@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-3.0.1.tgz#5c8d42b36cd4c80b92e5626a252f994ca6bfc953"
+ integrity sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==
+
+"@types/d3-scale-chromatic@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#103124777e8cdec85b20b51fd3397c682ee1e954"
+ integrity sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==
+
+"@types/d3-scale@*":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.2.tgz#41be241126af4630524ead9cb1008ab2f0f26e69"
+ integrity sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==
+ dependencies:
+ "@types/d3-time" "*"
+
+"@types/d3-selection@*":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.2.tgz#23e48a285b24063630bbe312cc0cfe2276de4a59"
+ integrity sha512-d29EDd0iUBrRoKhPndhDY6U/PYxOWqgIZwKTooy2UkBfU7TNZNpRho0yLWPxlatQrFWk2mnTu71IZQ4+LRgKlQ==
+
+"@types/d3-shape@*":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.0.tgz#1d87a6ddcf28285ef1e5c278ca4bdbc0658f3505"
+ integrity sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==
+ dependencies:
+ "@types/d3-path" "*"
+
+"@types/d3-time-format@*":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-4.0.0.tgz#ee7b6e798f8deb2d9640675f8811d0253aaa1946"
+ integrity sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==
+
+"@types/d3-time@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.0.tgz#e1ac0f3e9e195135361fa1a1d62f795d87e6e819"
+ integrity sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==
+
+"@types/d3-timer@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.0.tgz#e2505f1c21ec08bda8915238e397fb71d2fc54ce"
+ integrity sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==
+
+"@types/d3-transition@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.1.tgz#c9a96125567173d6163a6985b874f79154f4cc3d"
+ integrity sha512-Sv4qEI9uq3bnZwlOANvYK853zvpdKEm1yz9rcc8ZTsxvRklcs9Fx4YFuGA3gXoQN/c/1T6QkVNjhaRO/cWj94g==
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-zoom@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.1.tgz#4bfc7e29625c4f79df38e2c36de52ec3e9faf826"
+ integrity sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==
+ dependencies:
+ "@types/d3-interpolate" "*"
+ "@types/d3-selection" "*"
+
+"@types/d3@^7.4.0":
+ version "7.4.0"
+ resolved "https://registry.yarnpkg.com/@types/d3/-/d3-7.4.0.tgz#fc5cac5b1756fc592a3cf1f3dc881bf08225f515"
+ integrity sha512-jIfNVK0ZlxcuRDKtRS/SypEyOQ6UHaFQBKv032X45VvxSJ6Yi5G9behy9h6tNTHTDGh5Vq+KbmBjUWLgY4meCA==
+ dependencies:
+ "@types/d3-array" "*"
+ "@types/d3-axis" "*"
+ "@types/d3-brush" "*"
+ "@types/d3-chord" "*"
+ "@types/d3-color" "*"
+ "@types/d3-contour" "*"
+ "@types/d3-delaunay" "*"
+ "@types/d3-dispatch" "*"
+ "@types/d3-drag" "*"
+ "@types/d3-dsv" "*"
+ "@types/d3-ease" "*"
+ "@types/d3-fetch" "*"
+ "@types/d3-force" "*"
+ "@types/d3-format" "*"
+ "@types/d3-geo" "*"
+ "@types/d3-hierarchy" "*"
+ "@types/d3-interpolate" "*"
+ "@types/d3-path" "*"
+ "@types/d3-polygon" "*"
+ "@types/d3-quadtree" "*"
+ "@types/d3-random" "*"
+ "@types/d3-scale" "*"
+ "@types/d3-scale-chromatic" "*"
+ "@types/d3-selection" "*"
+ "@types/d3-shape" "*"
+ "@types/d3-time" "*"
+ "@types/d3-time-format" "*"
+ "@types/d3-timer" "*"
+ "@types/d3-transition" "*"
+ "@types/d3-zoom" "*"
+
"@types/debug@^4.0.0":
version "4.1.7"
resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz"
@@ -3261,6 +3471,11 @@
"@types/qs" "*"
"@types/range-parser" "*"
+"@types/geojson@*":
+ version "7946.0.8"
+ resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca"
+ integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==
+
"@types/glob@^7.1.1":
version "7.2.0"
resolved "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz"
@@ -4954,6 +5169,11 @@ comma-separated-tokens@^2.0.0:
resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz"
integrity sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==
+commander@7:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+ integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
commander@^2.20.3:
version "2.20.3"
resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"
@@ -5277,21 +5497,130 @@ d3-array@2, d3-array@^2.3.0:
dependencies:
internmap "^1.0.0"
+"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.1.6.tgz#0342c835925826f49b4d16eb7027aec334ffc97d"
+ integrity sha512-DCbBBNuKOeiR9h04ySRBMW52TFVc91O9wJziuyXw6Ztmy8D3oZbmCkOO3UHKC7ceNJsN2Mavo9+vwV8EAEUXzA==
+ dependencies:
+ internmap "1 - 2"
+
+d3-axis@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322"
+ integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==
+
+d3-brush@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c"
+ integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-drag "2 - 3"
+ d3-interpolate "1 - 3"
+ d3-selection "3"
+ d3-transition "3"
+
+d3-chord@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966"
+ integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==
+ dependencies:
+ d3-path "1 - 3"
+
"d3-color@1 - 2", d3-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e"
integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==
+"d3-color@1 - 3", d3-color@3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2"
+ integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==
+
+d3-contour@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-3.0.1.tgz#2c64255d43059599cd0dba8fe4cc3d51ccdd9bbd"
+ integrity sha512-0Oc4D0KyhwhM7ZL0RMnfGycLN7hxHB8CMmwZ3+H26PWAG0ozNuYG5hXSDNgmP1SgJkQMrlG6cP20HoaSbvcJTQ==
+ dependencies:
+ d3-array "2 - 3"
+
+d3-delaunay@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.2.tgz#7fd3717ad0eade2fc9939f4260acfb503f984e92"
+ integrity sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==
+ dependencies:
+ delaunator "5"
+
+"d3-dispatch@1 - 3", d3-dispatch@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e"
+ integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==
+
+"d3-drag@2 - 3", d3-drag@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba"
+ integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-selection "3"
+
+"d3-dsv@1 - 3", d3-dsv@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73"
+ integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==
+ dependencies:
+ commander "7"
+ iconv-lite "0.6"
+ rw "1"
+
+"d3-ease@1 - 3", d3-ease@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4"
+ integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==
+
+d3-fetch@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22"
+ integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==
+ dependencies:
+ d3-dsv "1 - 3"
+
+d3-force@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4"
+ integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-quadtree "1 - 3"
+ d3-timer "1 - 3"
+
"d3-format@1 - 2":
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767"
integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==
+"d3-format@1 - 3", d3-format@3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641"
+ integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==
+
d3-format@^1.4.4:
version "1.4.5"
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4"
integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==
+d3-geo@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.0.1.tgz#4f92362fd8685d93e3b1fae0fd97dc8980b1ed7e"
+ integrity sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==
+ dependencies:
+ d3-array "2.5.0 - 3"
+
+d3-hierarchy@3:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6"
+ integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==
+
"d3-interpolate@1 - 2", "d3-interpolate@1.2.0 - 2", d3-interpolate@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163"
@@ -5299,11 +5628,46 @@ d3-format@^1.4.4:
dependencies:
d3-color "1 - 2"
+"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d"
+ integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
+ dependencies:
+ d3-color "1 - 3"
+
d3-path@1:
version "1.0.9"
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf"
integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==
+"d3-path@1 - 3", d3-path@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.0.1.tgz#f09dec0aaffd770b7995f1a399152bf93052321e"
+ integrity sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==
+
+d3-polygon@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398"
+ integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==
+
+"d3-quadtree@1 - 3", d3-quadtree@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f"
+ integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==
+
+d3-random@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4"
+ integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==
+
+d3-scale-chromatic@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#15b4ceb8ca2bb0dcb6d1a641ee03d59c3b62376a"
+ integrity sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==
+ dependencies:
+ d3-color "1 - 3"
+ d3-interpolate "1 - 3"
+
d3-scale-chromatic@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-2.0.0.tgz#c13f3af86685ff91323dc2f0ebd2dabbd72d8bab"
@@ -5312,6 +5676,17 @@ d3-scale-chromatic@^2.0.0:
d3-color "1 - 2"
d3-interpolate "1 - 2"
+d3-scale@4:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396"
+ integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==
+ dependencies:
+ d3-array "2.10.0 - 3"
+ d3-format "1 - 3"
+ d3-interpolate "1.2.0 - 3"
+ d3-time "2.1.1 - 3"
+ d3-time-format "2 - 4"
+
d3-scale@^3.2.3:
version "3.3.0"
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.3.0.tgz#28c600b29f47e5b9cd2df9749c206727966203f3"
@@ -5323,6 +5698,18 @@ d3-scale@^3.2.3:
d3-time "^2.1.1"
d3-time-format "2 - 3"
+"d3-selection@2 - 3", d3-selection@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31"
+ integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==
+
+d3-shape@3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.1.0.tgz#c8a495652d83ea6f524e482fca57aa3f8bc32556"
+ integrity sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==
+ dependencies:
+ d3-path "1 - 3"
+
d3-shape@^1.2.2, d3-shape@^1.3.5:
version "1.3.7"
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7"
@@ -5337,6 +5724,13 @@ d3-shape@^1.2.2, d3-shape@^1.3.5:
dependencies:
d3-time "1 - 2"
+"d3-time-format@2 - 4", d3-time-format@4:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a"
+ integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==
+ dependencies:
+ d3-time "1 - 3"
+
"d3-time@1 - 2", d3-time@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682"
@@ -5344,11 +5738,81 @@ d3-shape@^1.2.2, d3-shape@^1.3.5:
dependencies:
d3-array "2"
+"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.0.0.tgz#65972cb98ae2d4954ef5c932e8704061335d4975"
+ integrity sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==
+ dependencies:
+ d3-array "2 - 3"
+
d3-time@^1.0.11:
version "1.1.0"
resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1"
integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==
+"d3-timer@1 - 3", d3-timer@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0"
+ integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
+
+"d3-transition@2 - 3", d3-transition@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f"
+ integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==
+ dependencies:
+ d3-color "1 - 3"
+ d3-dispatch "1 - 3"
+ d3-ease "1 - 3"
+ d3-interpolate "1 - 3"
+ d3-timer "1 - 3"
+
+d3-zoom@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3"
+ integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-drag "2 - 3"
+ d3-interpolate "1 - 3"
+ d3-selection "2 - 3"
+ d3-transition "2 - 3"
+
+d3@^7.4.4:
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/d3/-/d3-7.4.4.tgz#bfbf87487c37d3196efebd5a63e3a0ed8299d8ff"
+ integrity sha512-97FE+MYdAlV3R9P74+R3Uar7wUKkIFu89UWMjEaDhiJ9VxKvqaMxauImy8PC2DdBkdM2BxJOIoLxPrcZUyrKoQ==
+ dependencies:
+ d3-array "3"
+ d3-axis "3"
+ d3-brush "3"
+ d3-chord "3"
+ d3-color "3"
+ d3-contour "3"
+ d3-delaunay "6"
+ d3-dispatch "3"
+ d3-drag "3"
+ d3-dsv "3"
+ d3-ease "3"
+ d3-fetch "3"
+ d3-force "3"
+ d3-format "3"
+ d3-geo "3"
+ d3-hierarchy "3"
+ d3-interpolate "3"
+ d3-path "3"
+ d3-polygon "3"
+ d3-quadtree "3"
+ d3-random "3"
+ d3-scale "4"
+ d3-scale-chromatic "3"
+ d3-selection "3"
+ d3-shape "3"
+ d3-time "3"
+ d3-time-format "4"
+ d3-timer "3"
+ d3-transition "3"
+ d3-zoom "3"
+
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -5542,6 +6006,13 @@ del@^4.1.1:
pify "^4.0.1"
rimraf "^2.6.3"
+delaunator@5:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.0.tgz#60f052b28bd91c9b4566850ebf7756efe821d81b"
+ integrity sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==
+ dependencies:
+ robust-predicates "^3.0.0"
+
delay@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz"
@@ -6599,6 +7070,11 @@ forwarded@0.2.0:
resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+fp-ts@^2.12.1:
+ version "2.12.1"
+ resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.12.1.tgz#e389488bfd1507af06bd5965e97367edcd4fabad"
+ integrity sha512-oxvgqUYR6O9VkKXrxkJ0NOyU0FrE705MeqgBUMEPWyTu6Pwn768cJbHChw2XOBlgFLKfIHxjr2OOBFpv2mUGZw==
+
fraction.js@^4.0.13:
version "4.2.0"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
@@ -7251,7 +7727,7 @@ iconv-lite@0.4.24:
dependencies:
safer-buffer ">= 2.1.2 < 3"
-iconv-lite@^0.6.2:
+iconv-lite@0.6, iconv-lite@^0.6.2:
version "0.6.3"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
@@ -7386,6 +7862,11 @@ internal-slot@^1.0.3:
has "^1.0.3"
side-channel "^1.0.4"
+"internmap@1 - 2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009"
+ integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==
+
internmap@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95"
@@ -9184,6 +9665,11 @@ media-typer@0.3.0:
resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+"memoize-one@>=3.1.1 <6":
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
+ integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
+
memory-fs@^0.4.1:
version "0.4.1"
resolved "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz"
@@ -11609,6 +12095,19 @@ react-use-gesture@^9.1.3:
resolved "https://registry.npmjs.org/react-use-gesture/-/react-use-gesture-9.1.3.tgz"
integrity sha512-CdqA2SmS/fj3kkS2W8ZU8wjTbVBAIwDWaRprX7OKaj7HlGwBasGEFggmk5qNklknqk9zK/h8D355bEJFTpqEMg==
+react-virtualized-auto-sizer@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.6.tgz#66c5b1c9278064c5ef1699ed40a29c11518f97ca"
+ integrity sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ==
+
+react-window@^1.8.7:
+ version "1.8.7"
+ resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.7.tgz#5e9fd0d23f48f432d7022cdb327219353a15f0d4"
+ integrity sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==
+ dependencies:
+ "@babel/runtime" "^7.0.0"
+ memoize-one ">=3.1.1 <6"
+
react@^17.0.0, react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
@@ -11971,6 +12470,11 @@ rlp@^2.2.4:
dependencies:
bn.js "^5.2.0"
+robust-predicates@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a"
+ integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==
+
rpc-websockets@^7.4.12:
version "7.4.17"
resolved "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.4.17.tgz"
@@ -12006,6 +12510,11 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
+rw@1:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
+ integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==
+
rxjs@6, rxjs@^6.6.7:
version "6.6.7"
resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz"