From b6471a425a14b327b1dd8f03d997b3d6c77c2327 Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Sat, 24 Sep 2022 21:25:51 -0700 Subject: [PATCH] Fiddle around with everything, WIP FR charts --- web/components/answers/answers-graph.tsx | 238 ------ web/components/contract/contract-overview.tsx | 13 +- .../contract/contract-prob-graph.tsx | 690 +++++++++++++----- web/package.json | 4 +- web/pages/embed/[username]/[contractSlug].tsx | 21 +- yarn.lock | 500 ++++++++++++- 6 files changed, 1011 insertions(+), 455 deletions(-) delete mode 100644 web/components/answers/answers-graph.tsx diff --git a/web/components/answers/answers-graph.tsx b/web/components/answers/answers-graph.tsx deleted file mode 100644 index e4167d11..00000000 --- a/web/components/answers/answers-graph.tsx +++ /dev/null @@ -1,238 +0,0 @@ -import { DatumValue } from '@nivo/core' -import { ResponsiveLine } from '@nivo/line' -import dayjs from 'dayjs' -import { groupBy, sortBy, sumBy } from 'lodash' -import { memo } from 'react' - -import { Bet } from 'common/bet' -import { FreeResponseContract, MultipleChoiceContract } from 'common/contract' -import { getOutcomeProbability } from 'common/calculate' -import { useWindowSize } from 'web/hooks/use-window-size' - -const NUM_LINES = 6 - -export const AnswersGraph = memo(function AnswersGraph(props: { - contract: FreeResponseContract | MultipleChoiceContract - bets: Bet[] - height?: number -}) { - const { contract, bets, height } = props - const { createdTime, resolutionTime, closeTime, answers } = contract - const now = Date.now() - - const { probsByOutcome, sortedOutcomes } = computeProbsByOutcome( - bets, - contract - ) - - const isClosed = !!closeTime && now > closeTime - const latestTime = dayjs( - resolutionTime && isClosed - ? Math.min(resolutionTime, closeTime) - : isClosed - ? closeTime - : resolutionTime ?? now - ) - - const { width } = useWindowSize() - - const isLargeWidth = !width || width > 800 - const labelLength = isLargeWidth ? 50 : 20 - - // Add a fake datapoint so the line continues to the right - const endTime = latestTime.valueOf() - - const times = sortBy([ - createdTime, - ...bets.map((bet) => bet.createdTime), - endTime, - ]) - const dateTimes = times.map((time) => new Date(time)) - - const data = sortedOutcomes.map((outcome) => { - const betProbs = probsByOutcome[outcome] - // Add extra point for contract start and end. - const probs = [0, ...betProbs, betProbs[betProbs.length - 1]] - - const points = probs.map((prob, i) => ({ - x: dateTimes[i], - y: Math.round(prob * 100), - })) - - const answer = - answers?.find((answer) => answer.id === outcome)?.text ?? 'None' - const answerText = - answer.slice(0, labelLength) + (answer.length > labelLength ? '...' : '') - - return { id: answerText, data: points } - }) - - data.reverse() - - const yTickValues = [0, 25, 50, 75, 100] - - const numXTickValues = isLargeWidth ? 5 : 2 - const startDate = dayjs(contract.createdTime) - const endDate = startDate.add(1, 'hour').isAfter(latestTime) - ? latestTime.add(1, 'hours') - : latestTime - const includeMinute = endDate.diff(startDate, 'hours') < 2 - - const multiYear = !startDate.isSame(latestTime, 'year') - const lessThanAWeek = startDate.add(1, 'week').isAfter(latestTime) - - return ( -
- - formatTime(now, +d.valueOf(), multiYear, lessThanAWeek, lessThanAWeek) - } - axisBottom={{ - tickValues: numXTickValues, - format: (time) => - formatTime(now, +time, multiYear, lessThanAWeek, includeMinute), - }} - colors={[ - '#fca5a5', // red-300 - '#a5b4fc', // indigo-300 - '#86efac', // green-300 - '#fef08a', // yellow-200 - '#fdba74', // orange-300 - '#c084fc', // purple-400 - ]} - pointSize={0} - curve="stepAfter" - enableSlices="x" - enableGridX={!!width && width >= 800} - enableArea - areaOpacity={1} - margin={{ top: 20, right: 20, bottom: 25, left: 40 }} - legends={[ - { - anchor: 'top-left', - direction: 'column', - justify: false, - translateX: isLargeWidth ? 5 : 2, - translateY: 0, - itemsSpacing: 0, - itemTextColor: 'black', - itemDirection: 'left-to-right', - itemWidth: isLargeWidth ? 288 : 138, - itemHeight: 20, - itemBackground: 'white', - itemOpacity: 0.9, - symbolSize: 12, - effects: [ - { - on: 'hover', - style: { - itemBackground: 'rgba(255, 255, 255, 1)', - itemOpacity: 1, - }, - }, - ], - }, - ]} - /> -
- ) -}) - -function formatPercent(y: DatumValue) { - return `${Math.round(+y.toString())}%` -} - -function formatTime( - now: number, - time: number, - includeYear: boolean, - includeHour: boolean, - includeMinute: boolean -) { - const d = dayjs(time) - if (d.add(1, 'minute').isAfter(now) && d.subtract(1, 'minute').isBefore(now)) - return 'Now' - - let format: string - if (d.isSame(now, 'day')) { - format = '[Today]' - } else if (d.add(1, 'day').isSame(now, 'day')) { - format = '[Yesterday]' - } else { - format = 'MMM D' - } - - if (includeMinute) { - format += ', h:mma' - } else if (includeHour) { - format += ', ha' - } else if (includeYear) { - format += ', YYYY' - } - - return d.format(format) -} - -const computeProbsByOutcome = ( - bets: Bet[], - contract: FreeResponseContract | MultipleChoiceContract -) => { - const { totalBets, outcomeType } = contract - - const betsByOutcome = groupBy(bets, (bet) => bet.outcome) - const outcomes = Object.keys(betsByOutcome).filter((outcome) => { - const maxProb = Math.max( - ...betsByOutcome[outcome].map((bet) => bet.probAfter) - ) - return ( - (outcome !== '0' || outcomeType === 'MULTIPLE_CHOICE') && - maxProb > 0.02 && - totalBets[outcome] > 0.000000001 - ) - }) - - const trackedOutcomes = sortBy( - outcomes, - (outcome) => -1 * getOutcomeProbability(contract, outcome) - ).slice(0, NUM_LINES) - - const probsByOutcome = Object.fromEntries( - trackedOutcomes.map((outcome) => [outcome, [] as number[]]) - ) - const sharesByOutcome = Object.fromEntries( - Object.keys(betsByOutcome).map((outcome) => [outcome, 0]) - ) - - for (const bet of bets) { - const { outcome, shares } = bet - sharesByOutcome[outcome] += shares - - const sharesSquared = sumBy( - Object.values(sharesByOutcome).map((shares) => shares ** 2) - ) - - for (const outcome of trackedOutcomes) { - probsByOutcome[outcome].push( - sharesByOutcome[outcome] ** 2 / sharesSquared - ) - } - } - - return { probsByOutcome, sortedOutcomes: trackedOutcomes } -} diff --git a/web/components/contract/contract-overview.tsx b/web/components/contract/contract-overview.tsx index 139b30fe..a29679bd 100644 --- a/web/components/contract/contract-overview.tsx +++ b/web/components/contract/contract-overview.tsx @@ -2,7 +2,11 @@ import React from 'react' import { tradingAllowed } from 'web/lib/firebase/contracts' import { Col } from '../layout/col' -import { ContractProbGraph } from './contract-prob-graph' +import { + BinaryContractChart, + PseudoNumericContractChart, + ChoiceContractChart, +} from './contract-prob-graph' import { useUser } from 'web/hooks/use-user' import { Row } from '../layout/row' import { Linkify } from '../linkify' @@ -14,7 +18,6 @@ import { } from './contract-card' import { Bet } from 'common/bet' import BetButton, { BinaryMobileBetting } from '../bet-button' -import { AnswersGraph } from '../answers/answers-graph' import { Contract, CPMMContract, @@ -83,7 +86,7 @@ const BinaryOverview = (props: { contract: BinaryContract; bets: Bet[] }) => { /> - + {tradingAllowed(contract) && ( @@ -109,7 +112,7 @@ const ChoiceOverview = (props: { )} - + ) @@ -136,7 +139,7 @@ const PseudoNumericOverview = (props: { {tradingAllowed(contract) && } - + ) } diff --git a/web/components/contract/contract-prob-graph.tsx b/web/components/contract/contract-prob-graph.tsx index 60ef85b5..9f942d00 100644 --- a/web/components/contract/contract-prob-graph.tsx +++ b/web/components/contract/contract-prob-graph.tsx @@ -1,203 +1,521 @@ -import { DatumValue } from '@nivo/core' -import { ResponsiveLine, SliceTooltipProps } from '@nivo/line' -import { BasicTooltip } from '@nivo/tooltip' import dayjs from 'dayjs' -import { memo } from 'react' +import { memo, useEffect, useMemo, useRef, useState } from 'react' import { Bet } from 'common/bet' -import { getInitialProbability } from 'common/calculate' -import { BinaryContract, PseudoNumericContract } from 'common/contract' -import { useWindowSize } from 'web/hooks/use-window-size' +import { + getInitialProbability, + getOutcomeProbability, + getProbability, +} from 'common/calculate' +import { + Contract, + BinaryContract, + PseudoNumericContract, + FreeResponseContract, + MultipleChoiceContract, +} from 'common/contract' +import { useIsMobile } from 'web/hooks/use-is-mobile' import { formatLargeNumber } from 'common/util/format' +import { range, sortBy, groupBy, sumBy } from 'lodash' +import { useEvent } from 'web/hooks/use-event' -export const ContractProbGraph = memo(function ContractProbGraph(props: { - contract: BinaryContract | PseudoNumericContract - bets: Bet[] - height?: number -}) { - const { contract, height } = props - const { resolutionTime, closeTime, outcomeType } = contract - const now = Date.now() - const isBinary = outcomeType === 'BINARY' - const isLogScale = outcomeType === 'PSEUDO_NUMERIC' && contract.isLogScale +import * as d3 from 'd3' - const bets = props.bets.filter((bet) => !bet.isAnte && !bet.isRedemption) +const MARGIN = { top: 20, right: 10, bottom: 20, left: 40 } +const MARGIN_X = MARGIN.right + MARGIN.left +const MARGIN_Y = MARGIN.top + MARGIN.bottom - const startProb = getInitialProbability(contract) +type MultiPoint = readonly [Date, number[]] +type Point = readonly [Date, number] - const times = [contract.createdTime, ...bets.map((bet) => bet.createdTime)] - - const f: (p: number) => number = isBinary - ? (p) => p - : isLogScale - ? (p) => p * Math.log10(contract.max - contract.min + 1) - : (p) => p * (contract.max - contract.min) + contract.min - - const probs = [startProb, ...bets.map((bet) => bet.probAfter)].map(f) - - const isClosed = !!closeTime && now > closeTime - const latestTime = dayjs( - resolutionTime && isClosed - ? Math.min(resolutionTime, closeTime) - : isClosed - ? closeTime - : resolutionTime ?? now - ) - - // Add a fake datapoint so the line continues to the right - times.push(latestTime.valueOf()) - probs.push(probs[probs.length - 1]) - - const { width } = useWindowSize() - - const quartiles = !width || width < 800 ? [0, 50, 100] : [0, 25, 50, 75, 100] - - const yTickValues = isBinary - ? quartiles - : quartiles.map((x) => x / 100).map(f) - - const numXTickValues = !width || width < 800 ? 2 : 5 - const startDate = dayjs(times[0]) - const endDate = startDate.add(1, 'hour').isAfter(latestTime) - ? latestTime.add(1, 'hours') - : latestTime - const includeMinute = endDate.diff(startDate, 'hours') < 2 - - // Minimum number of points for the graph to have. For smooth tooltip movement - // If we aren't actually loading any data yet, skip adding extra points to let page load faster - // This fn runs again once DOM is finished loading - const totalPoints = width && bets.length ? (width > 800 ? 300 : 50) : 1 - - const timeStep: number = latestTime.diff(startDate, 'ms') / totalPoints - - const points: { x: Date; y: number }[] = [] - const s = isBinary ? 100 : 1 - - for (let i = 0; i < times.length - 1; i++) { - const p = probs[i] - const d0 = times[i] - const d1 = times[i + 1] - const msDiff = d1 - d0 - const numPoints = Math.floor(msDiff / timeStep) - points.push({ x: new Date(times[i]), y: s * p }) - if (numPoints > 1) { - const thisTimeStep: number = msDiff / numPoints - for (let n = 1; n < numPoints; n++) { - points.push({ x: new Date(d0 + thisTimeStep * n), y: s * p }) - } +const useElementWidth = (ref: React.RefObject) => { + const [width, setWidth] = useState() + useEffect(() => { + const handleResize = () => { + setWidth(ref.current?.clientWidth) } - } - - const data = [ - { id: 'Yes', data: points, color: isBinary ? '#11b981' : '#5fa5f9' }, - ] - - const multiYear = !startDate.isSame(latestTime, 'year') - const lessThanAWeek = startDate.add(8, 'day').isAfter(latestTime) - - const formatter = isBinary - ? formatPercent - : isLogScale - ? (x: DatumValue) => - formatLargeNumber(10 ** +x.valueOf() + contract.min - 1) - : (x: DatumValue) => formatLargeNumber(+x.valueOf()) - - return ( -
= 800 ? 250 : 150) }} - > - - formatTime(now, +d.valueOf(), multiYear, lessThanAWeek, lessThanAWeek) - } - axisBottom={{ - tickValues: numXTickValues, - format: (time) => - formatTime(now, +time, multiYear, lessThanAWeek, includeMinute), - }} - colors={{ datum: 'color' }} - curve="stepAfter" - enablePoints={false} - pointBorderWidth={1} - pointBorderColor="#fff" - enableSlices="x" - enableGridX={false} - enableArea - areaBaselineValue={isBinary || isLogScale ? 0 : contract.min} - margin={{ top: 20, right: 20, bottom: 25, left: 40 }} - animate={false} - sliceTooltip={SliceTooltip} - /> -
- ) -}) - -const SliceTooltip = ({ slice }: SliceTooltipProps) => { - return ( - [ - - {point.data[`yFormatted`]} {point.data['xFormatted']} - , - ])} - /> - ) + handleResize() + window.addEventListener('resize', handleResize) + return () => { + window.removeEventListener('resize', handleResize) + } + }, [ref]) + return width } -function formatPercent(y: DatumValue) { - return `${Math.round(+y.toString())}%` -} - -function formatTime( - now: number, - time: number, - includeYear: boolean, - includeHour: boolean, - includeMinute: boolean -) { - const d = dayjs(time) +const formatDate = ( + date: Date, + opts: { includeYear: boolean; includeHour: boolean; includeMinute: boolean } +) => { + const { includeYear, includeHour, includeMinute } = opts + const d = dayjs(date) + const now = Date.now() if (d.add(1, 'minute').isAfter(now) && d.subtract(1, 'minute').isBefore(now)) return 'Now' - - let format: string if (d.isSame(now, 'day')) { - format = '[Today]' + return '[Today]' } else if (d.add(1, 'day').isSame(now, 'day')) { - format = '[Yesterday]' + return '[Yesterday]' } else { - format = 'MMM D' + let format = 'MMM D' + if (includeMinute) { + format += ', h:mma' + } else if (includeHour) { + format += ', ha' + } else if (includeYear) { + format += ', YYYY' + } + return d.format(format) } - - if (includeMinute) { - format += ', h:mma' - } else if (includeHour) { - format += ', ha' - } else if (includeYear) { - format += ', YYYY' - } - - return d.format(format) +} + +const getDateRange = (contract: Contract) => { + const { createdTime, closeTime, resolutionTime } = contract + const now = Date.now() + const isClosed = !!closeTime && now > closeTime + const endDate = resolutionTime ?? (isClosed ? closeTime : now) + // the graph should be minimum an hour wide + const adjustedEndDate = dayjs(createdTime).add(1, 'hour').isAfter(endDate) + ? dayjs(endDate).add(1, 'hours') + : dayjs(endDate) + return [new Date(createdTime), adjustedEndDate.toDate()] as const +} + +const getTickValues = (min: number, max: number, n: number) => { + const step = (max - min) / (n - 1) + return [min, ...range(1, n - 1).map((i) => min + step * i), max] +} + +const getMultiChartData = ( + contract: FreeResponseContract | MultipleChoiceContract, + bets: Bet[] +) => { + const { totalBets, outcomeType } = contract + + const sortedBets = sortBy(bets, (b) => b.createdTime) + const betsByOutcome = groupBy(sortedBets, (bet) => bet.outcome) + const outcomes = Object.keys(betsByOutcome).filter((outcome) => { + const maxProb = Math.max( + ...betsByOutcome[outcome].map((bet) => bet.probAfter) + ) + return ( + (outcome !== '0' || outcomeType === 'MULTIPLE_CHOICE') && + maxProb > 0.02 && + totalBets[outcome] > 0.000000001 + ) + }) + + const trackedOutcomes = sortBy( + outcomes, + (outcome) => -1 * getOutcomeProbability(contract, outcome) + ) + .slice(0, 10) + .reverse() + + const points: MultiPoint[] = [] + + const sharesByOutcome = Object.fromEntries( + Object.keys(betsByOutcome).map((outcome) => [outcome, 0]) + ) + + for (const bet of sortedBets) { + const { outcome, shares } = bet + sharesByOutcome[outcome] += shares + + const sharesSquared = sumBy( + Object.values(sharesByOutcome).map((shares) => shares ** 2) + ) + points.push([ + new Date(bet.createdTime), + trackedOutcomes.map( + (outcome) => sharesByOutcome[outcome] ** 2 / sharesSquared + ), + ]) + } + + const allPoints: MultiPoint[] = [ + [new Date(contract.createdTime), trackedOutcomes.map((_) => 0)], + ...points, + [ + new Date(Date.now()), + trackedOutcomes.map((outcome) => + getOutcomeProbability(contract, outcome) + ), + ], + ] + return { points: allPoints, labels: trackedOutcomes } +} + +const getChartData = ( + contract: BinaryContract | PseudoNumericContract, + bets: Bet[] +): Point[] => { + const getY = (p: number) => { + if (contract.outcomeType === 'PSEUDO_NUMERIC') { + const { min, max } = contract + return p * (max - min) + min + } else { + return p + } + } + const sortedBets = sortBy(bets, (b) => b.createdTime) + const startProb = getInitialProbability(contract) + const endProb = getProbability(contract) + return [ + [new Date(contract.createdTime), getY(startProb)] as const, + ...sortedBets.map( + (b) => [new Date(b.createdTime), getY(b.probAfter)] as const + ), + [new Date(Date.now()), getY(endProb)] as const, + ] +} + +const XAxis = (props: { w: number; h: number; scale: d3.AxisScale }) => { + const { h, scale } = props + const axisRef = useRef(null) + const [start, end] = scale.domain() + const fmt = getFormatterForDateRange(start, end) + useEffect(() => { + if (axisRef.current != null) { + const axis = d3.axisBottom(scale).tickFormat(fmt) + d3.select(axisRef.current) + .call(axis) + .call((g) => g.select('.domain').remove()) + } + }) + return +} + +const YAxis = (props: { + w: number + h: number + scale: d3.AxisScale + pct?: boolean +}) => { + const { w, h, scale, pct } = props + const axisRef = useRef(null) + const [min, max] = scale.domain() + const tickValues = getTickValues(min, max, h < 200 ? 3 : 5) + const fmt = (n: number) => (pct ? d3.format('.0%')(n) : formatLargeNumber(n)) + useEffect(() => { + if (axisRef.current != null) { + const axis = d3.axisLeft(scale).tickValues(tickValues).tickFormat(fmt) + d3.select(axisRef.current) + .call(axis) + .call((g) => g.select('.domain').remove()) + .call((g) => + g.selectAll('.tick line').attr('x2', w).attr('stroke-opacity', 0.1) + ) + } + }) + return +} + +const LinePathInternal = ( + props: { + data: P[] + px: number | ((p: P) => number) + py: number | ((p: P) => number) + } & React.SVGProps +) => { + const { data, px, py, ...rest } = props + const line = d3.line

(px, py).curve(d3.curveStepAfter) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return +} +const LinePath = memo(LinePathInternal) as typeof LinePathInternal + +const AreaPathInternal = ( + props: { + data: P[] + px: number | ((p: P) => number) + py0: number | ((p: P) => number) + py1: number | ((p: P) => number) + } & React.SVGProps +) => { + const { data, px, py0, py1, ...rest } = props + const area = d3.area

(px, py0, py1).curve(d3.curveStepAfter) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return +} +const AreaPath = memo(AreaPathInternal) as typeof AreaPathInternal + +const TwoAxisChart = (props: { + children: React.ReactNode + w: number + h: number + xScale: d3.ScaleTime + yScale: d3.ScaleContinuousNumeric + onMouseOver?: (ev: React.PointerEvent) => void + onMouseLeave?: (ev: React.PointerEvent) => void + pct?: boolean +}) => { + const { children, w, h, xScale, yScale, onMouseOver, onMouseLeave, pct } = + props + const innerW = w - MARGIN_X + const innerH = h - MARGIN_Y + return ( + + + + + {children} + + + + ) +} + +export const MultiValueHistoryChart = (props: { + data: MultiPoint[] + w: number + h: number + labels: readonly string[] + colors: readonly string[] + xScale: d3.ScaleTime + yScale: d3.ScaleContinuousNumeric + pct?: boolean +}) => { + const { colors, data, xScale, yScale, labels, w, h, pct } = props + const tooltipRef = useRef(null) + const stack = d3 + .stack() + .keys(range(0, labels.length)) + .value((p, o) => p[1][o]) + + return ( +

+
+ + {stack(data).map((s, i) => ( + + xScale(p.data[0])} + py={(p) => yScale(p[1])} + stroke={colors[i]} + /> + xScale(p.data[0])} + py0={(p) => yScale(p[0])} + py1={(p) => yScale(p[1])} + fill={colors[i]} + /> + + ))} + +
+ ) +} + +export const SingleValueHistoryChart = (props: { + data: Point[] + w: number + h: number + color: string + xScale: d3.ScaleTime + yScale: d3.ScaleContinuousNumeric + pct?: boolean +}) => { + const { color, data, xScale, yScale, pct, w, h } = props + const tooltipRef = useRef(null) + const dates = useMemo(() => data.map(([d]) => d), [data]) + const [startDate, endDate] = xScale.domain().map(dayjs) + const includeYear = !startDate.isSame(endDate, 'year') + const includeHour = startDate.add(8, 'day').isAfter(endDate) + const includeMinute = endDate.diff(startDate, 'hours') < 2 + const formatX = (d: Date) => + formatDate(d, { includeYear, includeHour, includeMinute }) + const formatY = (n: number) => + pct ? d3.format('.0%')(n) : formatLargeNumber(n) + + const onMouseOver = useEvent((event: React.PointerEvent) => { + const tt = tooltipRef.current + if (tt != null) { + const [mouseX, mouseY] = d3.pointer(event) + const date = xScale.invert(mouseX) + const [_, prob] = data[d3.bisectCenter(dates, date)] + tt.innerHTML = `${formatY(prob)} ${formatX(date)}` + tt.style.display = 'block' + tt.style.top = mouseY - 10 + 'px' + tt.style.left = mouseX + 20 + 'px' + } + }) + + const onMouseLeave = useEvent(() => { + const tt = tooltipRef.current + if (tt != null) { + tt.style.display = 'none' + } + }) + + return ( +
+
+ + xScale(p[0])} + py={(p) => yScale(p[1])} + stroke={color} + /> + xScale(p[0])} + py0={yScale(0)} + py1={(p) => yScale(p[1])} + fill={color} + fillOpacity={0.3} + /> + +
+ ) +} + +export const ContractChart = (props: { + contract: Contract + bets: Bet[] + height?: number +}) => { + const { contract } = props + switch (contract.outcomeType) { + case 'BINARY': + return + case 'PSEUDO_NUMERIC': + return + case 'FREE_RESPONSE': + case 'MULTIPLE_CHOICE': + return + default: + return null + } +} + +const getFormatterForDateRange = (start: Date, end: Date) => { + const opts = { + includeYear: !dayjs(start).isSame(end, 'year'), + includeHour: dayjs(start).add(8, 'day').isAfter(end), + includeMinute: dayjs(end).diff(start, 'hours') < 2, + } + return (d: Date) => formatDate(d, opts) +} + +export const PseudoNumericContractChart = (props: { + contract: PseudoNumericContract + bets: Bet[] + height?: number +}) => { + const { contract, bets } = props + const data = useMemo(() => getChartData(contract, bets), [contract, bets]) + const isMobile = useIsMobile(800) + const containerRef = useRef(null) + const width = useElementWidth(containerRef) ?? 0 + const height = props.height ?? isMobile ? 150 : 250 + const scaleType = contract.isLogScale ? d3.scaleLog : d3.scaleLinear + const xScale = d3.scaleTime(getDateRange(contract), [0, width - MARGIN_X]) + const yScale = scaleType([contract.min, contract.max], [height - MARGIN_Y, 0]) + return ( +
+ {width && ( + + )} +
+ ) +} + +export const BinaryContractChart = (props: { + contract: BinaryContract + bets: Bet[] + height?: number +}) => { + const { contract, bets } = props + const data = useMemo(() => getChartData(contract, bets), [contract, bets]) + const isMobile = useIsMobile(800) + const containerRef = useRef(null) + const width = useElementWidth(containerRef) ?? 0 + const height = props.height ?? isMobile ? 150 : 250 + const xScale = d3.scaleTime(getDateRange(contract), [0, width - MARGIN_X]) + const yScale = d3.scaleLinear([0, 1], [height - MARGIN_Y, 0]) + return ( +
+ {width && ( + + )} +
+ ) +} + +export const ChoiceContractChart = (props: { + contract: FreeResponseContract | MultipleChoiceContract + bets: Bet[] + height?: number +}) => { + const { contract, bets } = props + const data = useMemo( + () => getMultiChartData(contract, bets), + [contract, bets] + ) + const isMobile = useIsMobile(800) + const containerRef = useRef(null) + const width = useElementWidth(containerRef) ?? 0 + const height = props.height ?? isMobile ? 150 : 250 + const xScale = d3.scaleTime(getDateRange(contract), [0, width - MARGIN_X]) + const yScale = d3.scaleLinear([0, 1], [height - MARGIN_Y, 0]) + return ( +
+ {width && ( + + )} +
+ ) } diff --git a/web/package.json b/web/package.json index 3ccbc96c..570139f4 100644 --- a/web/package.json +++ b/web/package.json @@ -39,6 +39,7 @@ "browser-image-compression": "2.0.0", "clsx": "1.1.1", "cors": "2.8.5", + "d3": "7.6.1", "daisyui": "1.16.4", "dayjs": "1.10.7", "firebase": "9.9.3", @@ -56,9 +57,9 @@ "react-expanding-textarea": "2.3.5", "react-hot-toast": "2.2.0", "react-instantsearch-hooks-web": "6.24.1", + "react-masonry-css": "1.0.16", "react-query": "3.39.0", "react-twitter-embed": "4.0.4", - "react-masonry-css": "1.0.16", "string-similarity": "^4.0.4", "tippy.js": "6.3.7" }, @@ -66,6 +67,7 @@ "@tailwindcss/forms": "0.4.0", "@tailwindcss/line-clamp": "^0.3.1", "@tailwindcss/typography": "^0.5.1", + "@types/d3": "7.4.0", "@types/lodash": "4.14.178", "@types/node": "16.11.11", "@types/react": "17.0.43", diff --git a/web/pages/embed/[username]/[contractSlug].tsx b/web/pages/embed/[username]/[contractSlug].tsx index 75a9ad05..f804a78e 100644 --- a/web/pages/embed/[username]/[contractSlug].tsx +++ b/web/pages/embed/[username]/[contractSlug].tsx @@ -2,7 +2,6 @@ import { Bet } from 'common/bet' import { Contract } from 'common/contract' import { DOMAIN } from 'common/envs/constants' import { useState } from 'react' -import { AnswersGraph } from 'web/components/answers/answers-graph' import { BetInline } from 'web/components/bet-inline' import { Button } from 'web/components/button' import { @@ -12,8 +11,7 @@ import { PseudoNumericResolutionOrExpectation, } from 'web/components/contract/contract-card' import { MarketSubheader } from 'web/components/contract/contract-details' -import { ContractProbGraph } from 'web/components/contract/contract-prob-graph' -import { NumericGraph } from 'web/components/contract/numeric-graph' +import { ContractChart } from 'web/components/contract/contract-prob-graph' import { Col } from 'web/components/layout/col' import { Row } from 'web/components/layout/row' import { Spacer } from 'web/components/layout/spacer' @@ -134,22 +132,7 @@ export function ContractEmbed(props: { contract: Contract; bets: Bet[] }) { )}
- {(isBinary || isPseudoNumeric) && ( - - )} - - {(outcomeType === 'FREE_RESPONSE' || - outcomeType === 'MULTIPLE_CHOICE') && ( - - )} - - {outcomeType === 'NUMERIC' && ( - - )} +
) diff --git a/yarn.lock b/yarn.lock index 9829f0b1..17a065f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3250,6 +3250,216 @@ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== +"@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.3" + resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.3.tgz#57be7da68e7d9c9b29efefd8ea5a9ef1171e42ba" + integrity sha512-Mw5cf6nlW1MlefpD9zrshZ+DAWL4IQ5LnWfRheW6xwsdaWOb6IRRu2H7XPAQcyXEx1D7XQWgdoKR83ui1/HlEA== + +"@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.2" + resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.2.tgz#393dc3e3d55009a43cc6f252e73fccab6d78a8a4" + integrity sha512-jo5o/Rf+/u6uerJ/963Dc39NI16FQzqwOc54bwvksGAdVfvDrqDpVeq95bEvPtBwLCVZutAEyAtmSyEMxN7vxQ== + 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/eslint-scope@^3.7.3": version "3.7.3" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" @@ -3299,6 +3509,11 @@ "@types/express-serve-static-core" "*" "@types/serve-static" "*" +"@types/geojson@*": + version "7946.0.10" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.10.tgz#6dfbf5ea17142f7f9a043809f1cd4c448cb68249" + integrity sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA== + "@types/google.maps@^3.45.3": version "3.49.0" resolved "https://registry.yarnpkg.com/@types/google.maps/-/google.maps-3.49.0.tgz#26fcf3d86ecbc6545db0e6691a434ec8132df48b" @@ -4834,6 +5049,11 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== +commander@7, commander@^7.2.0: + 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.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -4844,11 +5064,6 @@ commander@^5.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== -commander@^7.2.0: - 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@^8.0.0, commander@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" @@ -5242,11 +5457,60 @@ 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, d3-array@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.0.tgz#15bf96cd9b7333e02eb8de8053d78962eafcff14" + integrity sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g== + 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@4: + version "4.0.0" + resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-4.0.0.tgz#5a1337c6da0d528479acdb5db54bc81a0ff2ec6b" + integrity sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw== + dependencies: + d3-array "^3.2.0" + +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-delaunay@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-5.3.0.tgz#b47f05c38f854a4e7b3cea80e0bb12e57398772d" @@ -5254,16 +5518,76 @@ d3-delaunay@^5.3.0: dependencies: delaunator "4" +"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" @@ -5271,11 +5595,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" @@ -5284,6 +5643,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" @@ -5295,6 +5665,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.3.5: version "1.3.7" resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" @@ -5309,6 +5691,13 @@ 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" @@ -5316,11 +5705,81 @@ 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.6.1: + version "7.6.1" + resolved "https://registry.yarnpkg.com/d3/-/d3-7.6.1.tgz#b21af9563485ed472802f8c611cc43be6c37c40c" + integrity sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw== + dependencies: + d3-array "3" + d3-axis "3" + d3-brush "3" + d3-chord "3" + d3-color "3" + d3-contour "4" + 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" + daisyui@1.16.4: version "1.16.4" resolved "https://registry.yarnpkg.com/daisyui/-/daisyui-1.16.4.tgz#52773401c0962e37ef40507d29f0e513c7f2856f" @@ -5464,6 +5923,13 @@ delaunator@4: resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-4.0.1.tgz#3d779687f57919a7a418f8ab947d3bddb6846957" integrity sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag== +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" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -7381,6 +7847,13 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" @@ -7519,6 +7992,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" @@ -10672,6 +11150,11 @@ rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +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== + rope-sequence@^1.3.0: version "1.3.3" resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.3.tgz#3f67fc106288b84b71532b4a5fd9d4881e4457f0" @@ -10699,6 +11182,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.6.3: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" @@ -10723,7 +11211,7 @@ safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==