2021-10-06 11:00:09 +00:00
/* Definitions */
2021-11-25 11:09:17 +00:00
const elementsDocument = '../data/listOfMoralGoods.json'
2021-10-06 11:00:09 +00:00
const domain = 250
/* Imports */
2021-06-06 21:14:05 +00:00
import Head from 'next/head'
import React , { useState } from "react" ;
2021-06-07 11:16:28 +00:00
import fs from 'fs' ;
import path from 'path' ;
2021-09-22 19:45:18 +00:00
import { DrawGraph , removeOldSvg } from '../lib/labeledgraph' ;
2021-06-12 14:13:13 +00:00
import { SliderElement , SubmitSliderButton } from "../lib/slider" ;
2021-09-22 19:45:18 +00:00
import { DisplayElement } from '../lib/displayElement'
import { DisplayAsMarkdown } from '../lib/displayAsMarkdown'
import { CreateTableWithDistances } from '../lib/findPaths'
import { TextAreaForJson } from "../lib/textAreaForJson"
2021-10-06 08:33:54 +00:00
import { pushToMongo } from "../lib/pushToMongo.js"
2021-11-25 00:42:34 +00:00
import { toLocale , transformSliderValueToPracticalValue , transformSliderValueToActualValue , numToAlphabeticalString } from "../lib/utils.js"
2021-06-07 11:16:28 +00:00
2021-10-06 11:00:09 +00:00
/* Helpers */
2021-06-07 11:16:28 +00:00
let increasingList = ( n ) => Array . from ( Array ( n ) . keys ( ) )
2021-11-25 11:58:50 +00:00
let buildLinks = quantitativeComparisons => quantitativeComparisons . map ( ( [ element1 , element2 , distance , reasoning ] ) => ( { source : element1 , target : element2 , distance : distance , reasoning : reasoning } ) )
2021-06-07 11:16:28 +00:00
2021-09-22 19:45:18 +00:00
Array . prototype . containsArray = function ( val ) {
2021-06-06 21:14:05 +00:00
var hash = { } ;
2021-09-22 19:45:18 +00:00
for ( var i = 0 ; i < this . length ; i ++ ) {
hash [ this [ i ] ] = i ;
2021-06-06 21:14:05 +00:00
}
return hash . hasOwnProperty ( val ) ;
}
2021-09-22 19:45:18 +00:00
let checkIfListIsOrdered = ( arr , binaryComparisons ) => {
2021-06-06 21:14:05 +00:00
let l = arr . length
let isOrdered = true
2021-09-22 19:45:18 +00:00
for ( let i = 0 ; i < l - 1 ; i ++ ) {
isOrdered = isOrdered && binaryComparisons . containsArray ( [ arr [ i ] , arr [ i + 1 ] ] )
2021-06-06 21:14:05 +00:00
}
return isOrdered
}
2021-11-25 00:42:34 +00:00
let displayFunctionSliderInner = ( value ) => {
2021-06-06 22:18:40 +00:00
let result
2021-09-22 19:45:18 +00:00
if ( value >= 0 ) {
2021-10-06 11:00:09 +00:00
result = toLocale ( transformSliderValueToPracticalValue ( value ) )
2021-09-22 19:45:18 +00:00
} else {
2021-10-06 11:00:09 +00:00
let inverseresult = toLocale ( transformSliderValueToPracticalValue ( - value ) )
2021-11-25 00:42:34 +00:00
if ( inverseresult == 1 ) {
2021-11-15 13:40:20 +00:00
result = '1'
2021-11-25 00:42:34 +00:00
} else {
2021-11-15 13:40:20 +00:00
result = ` 1/ ${ inverseresult } `
}
2021-06-06 22:18:40 +00:00
}
2021-11-25 00:42:34 +00:00
return result
}
let displayFunctionSlider = ( value ) => {
let result = displayFunctionSliderInner ( value )
2021-06-06 22:18:40 +00:00
result = ` The first option is ${ result } x as valuable as the second one `
return result
} ;
2021-11-25 11:58:50 +00:00
let nicelyFormatLinks = ( quantitativeComparisons , listOfElements ) => quantitativeComparisons . map ( ( [ element1 , element2 , distance , reasoning ] ) => ( { source : listOfElements [ element1 ] . name , target : listOfElements [ element2 ] . name , distance : distance , reasoning : reasoning } ) )
2021-06-07 14:01:15 +00:00
2021-06-10 21:52:33 +00:00
/* React components */
// fs can only be used here.
2021-06-07 11:16:28 +00:00
export async function getStaticProps ( ) {
//getServerSideProps
// const { metaforecasts } = await getForecasts();
2021-09-22 19:45:18 +00:00
const directory = path . join ( process . cwd ( ) , "pages" )
2021-10-06 11:00:09 +00:00
let listOfElementsDefault = JSON . parse ( fs . readFileSync ( path . join ( directory , elementsDocument ) , 'utf8' ) ) ;
2021-06-10 21:52:33 +00:00
//console.log(directory)
2021-06-07 11:16:28 +00:00
//console.log("metaforecasts", metaforecasts)
return {
props : {
2021-10-06 11:00:09 +00:00
listOfElementsDefault
2021-06-07 11:16:28 +00:00
} ,
} ;
}
2021-06-10 21:52:33 +00:00
// Main react component
2021-09-22 19:45:18 +00:00
export default function Home ( { listOfElementsDefault } ) {
2021-06-06 21:14:05 +00:00
// State
2021-09-22 19:45:18 +00:00
let initialListOfElements = listOfElementsDefault . map ( ( element , i ) => ( { ... element , id : i } ) )
2021-06-12 14:13:13 +00:00
let initialPosList = increasingList ( listOfElementsDefault . length ) // [0,1,2,3,4]
//let listOfElements = listOfElementsDefault.map((element, i) => ({...element, id: i}))
//let list = increasingList(listOfElementsDefault.length) // [0,1,2,3,4]
2021-06-06 22:18:40 +00:00
2021-06-12 14:13:13 +00:00
//let initialComparePair = [list[list.length-2], list[list.length-1]]
2021-09-22 19:45:18 +00:00
let initialComparePair = [ initialPosList [ initialPosList . length - 2 ] , initialPosList [ initialPosList . length - 1 ] ]
2021-11-25 00:42:34 +00:00
let initialSliderValue = 1
2021-11-25 11:58:50 +00:00
let initialReasoning = ''
2021-06-12 14:13:13 +00:00
let initialBinaryComparisons = [ ]
let initialQuantitativeComparisons = [ ]
let initialIsListOdered = false
let initialOrderedList = [ ]
let initialShowAdvancedOptions = false
let initialShowComparisons = false
let initialShowChangeDataSet = false
2021-06-10 21:52:33 +00:00
2021-06-12 14:13:13 +00:00
const [ listOfElements , setListOfElements ] = useState ( initialListOfElements )
const [ posList , setPosList ] = useState ( initialPosList )
//const posList = initialPosList
// let listOfElements = initialListOfElements
2021-06-06 22:18:40 +00:00
2021-06-12 14:13:13 +00:00
const [ toComparePair , setToComparePair ] = useState ( initialComparePair )
const [ sliderValue , setSliderValue ] = useState ( initialSliderValue )
2021-11-25 11:58:50 +00:00
const [ reasoning , setReasoning ] = useState ( initialReasoning )
2021-06-12 14:13:13 +00:00
const [ binaryComparisons , setBinaryComparisons ] = useState ( initialBinaryComparisons )
const [ quantitativeComparisons , setQuantitativeComparisons ] = useState ( initialQuantitativeComparisons ) // More expressive, but more laborious to search through. For the ordering step, I only manipulate the binaryComparisons.
2021-09-22 19:45:18 +00:00
const [ isListOrdered , setIsListOrdered ] = useState ( initialIsListOdered )
2021-06-12 14:13:13 +00:00
const [ orderedList , setOrderedList ] = useState ( initialOrderedList )
let [ showAdvancedOptions , changeShowAdvanceOptions ] = useState ( initialShowAdvancedOptions ) ;
let [ showComparisons , changeShowComparisons ] = useState ( initialShowComparisons ) ;
let [ showChangeDataSet , changeshowChangeDataSet ] = useState ( initialShowChangeDataSet ) ;
let restart = ( posList ) => {
2021-09-22 19:45:18 +00:00
setToComparePair ( [ posList [ posList . length - 2 ] , posList [ posList . length - 1 ] ] )
2021-06-12 14:13:13 +00:00
setSliderValue ( initialSliderValue )
setBinaryComparisons ( initialBinaryComparisons )
setQuantitativeComparisons ( initialQuantitativeComparisons )
setIsListOrdered ( initialIsListOdered )
setOrderedList ( initialOrderedList )
removeOldSvg ( )
}
2021-09-22 19:45:18 +00:00
2021-06-12 14:13:13 +00:00
let changeDataSet = ( listOfElementsNew ) => {
2021-09-22 19:45:18 +00:00
listOfElementsNew =
listOfElementsNew . map ( ( element , i ) => ( { ... element , id : i } ) )
2021-06-12 14:13:13 +00:00
let newPosList = increasingList ( listOfElementsNew . length )
setListOfElements ( listOfElementsNew )
setPosList ( increasingList ( listOfElementsNew . length ) )
2021-09-22 19:45:18 +00:00
setToComparePair ( [ newPosList [ newPosList . length - 2 ] , newPosList [ newPosList . length - 1 ] ] )
2021-06-12 14:13:13 +00:00
restart ( newPosList )
}
2021-06-06 21:14:05 +00:00
// Manipulations
2021-06-06 22:18:40 +00:00
let compareTwoElements = ( newBinaryComparisons , element1 , element2 ) => {
let element1Greater = newBinaryComparisons . containsArray ( [ element1 , element2 ] )
let element2Greater = newBinaryComparisons . containsArray ( [ element2 , element1 ] )
2021-09-22 19:45:18 +00:00
if ( element1Greater || element2Greater ) {
2021-06-06 21:14:05 +00:00
return element1Greater && ! element2Greater
2021-09-22 19:45:18 +00:00
} else {
2021-06-06 21:14:05 +00:00
setToComparePair ( [ element1 , element2 ] )
2021-06-10 21:52:33 +00:00
//console.log(`No comparison found between ${element1} and ${element2}`)
//console.log(`Comparisons:`)
//console.log(JSON.stringify(newBinaryComparisons, null, 4));
2021-06-06 21:14:05 +00:00
return "No comparison found"
}
}
2021-06-06 22:18:40 +00:00
function merge ( newBinaryComparisons , left , right ) {
2021-06-06 21:14:05 +00:00
let sortedArr = [ ] ; // the sorted elements will go here
2021-09-22 19:45:18 +00:00
2021-06-06 21:14:05 +00:00
while ( left . length && right . length ) {
// insert the biggest element to the sortedArr
2021-06-06 22:18:40 +00:00
let comparison = compareTwoElements ( newBinaryComparisons , left [ 0 ] , right [ 0 ] )
2021-09-22 19:45:18 +00:00
if ( comparison == "No comparison found" ) {
2021-06-06 21:14:05 +00:00
return "No comparison found; unable to proceed"
}
else if ( comparison ) { // left[0] > right[0]
sortedArr . push ( left . shift ( ) ) ;
} else {
sortedArr . push ( right . shift ( ) ) ;
}
}
2021-09-22 19:45:18 +00:00
2021-06-06 21:14:05 +00:00
// use spread operator and create a new array, combining the three arrays
return [ ... sortedArr , ... left , ... right ] ; // if they don't have the same size, the remaining ones will be greater than the ones before
}
2021-09-22 19:45:18 +00:00
function mergeSort ( { array , comparisons } ) {
if ( array == "No comparison found; unable to proceed" ) {
return "No comparison found; unable to proceed"
2021-06-06 21:14:05 +00:00
}
2021-06-12 14:13:13 +00:00
const half = array . length / 2 ;
2021-09-22 19:45:18 +00:00
2021-06-06 21:14:05 +00:00
// the base case is array length <=1
2021-06-12 14:13:13 +00:00
if ( array . length <= 1 ) {
return array ;
2021-06-06 21:14:05 +00:00
}
2021-09-22 19:45:18 +00:00
2021-06-12 14:13:13 +00:00
const left = array . slice ( 0 , half ) ; // the first half of the array
const right = array . slice ( half , array . length ) // Note that splice is destructive.
2021-09-22 19:45:18 +00:00
let orderedFirstHalf = mergeSort ( { array : left , comparisons } )
let orderedSecondHalf = mergeSort ( { array : right , comparisons } )
if ( orderedFirstHalf != "No comparison found; unable to proceed" && orderedSecondHalf != "No comparison found; unable to proceed" ) {
2021-06-12 14:13:13 +00:00
let result = merge ( comparisons , orderedFirstHalf , orderedSecondHalf ) ;
2021-06-06 21:14:05 +00:00
return result
2021-09-22 19:45:18 +00:00
} else {
return "No comparison found; unable to proceed"
2021-06-06 21:14:05 +00:00
}
}
2021-06-12 14:13:13 +00:00
let nextStepSimple = ( posList , binaryComparisons , element1 , element2 ) => {
2021-06-10 21:52:33 +00:00
//console.log("Binary comparisons: ")
//console.log(JSON.stringify(binaryComparisons, null, 4));
2021-06-06 22:18:40 +00:00
2021-06-06 21:14:05 +00:00
let newComparison = [ element1 , element2 ] // [element1, element2]
2021-06-06 22:18:40 +00:00
let newBinaryComparisons = [ ... binaryComparisons , newComparison ]
2021-06-10 21:52:33 +00:00
//console.log("New binaryComparisons: ")
//console.log(JSON.stringify(newBinaryComparisons, null, 4));
2021-09-22 19:45:18 +00:00
setBinaryComparisons ( newBinaryComparisons )
let result = mergeSort ( { array : posList , comparisons : newBinaryComparisons } )
2021-06-10 21:52:33 +00:00
//console.log(result)
2021-09-22 19:45:18 +00:00
if ( result != "No comparison found; unable to proceed" && checkIfListIsOrdered ( result , newBinaryComparisons ) ) {
2021-06-12 14:13:13 +00:00
// console.log(`isListOrdered: ${isListOrdered}`)
console . log ( "poslist@nextStepSimple" )
console . log ( posList )
console . log ( "result@nextStepSimple" )
console . log ( result )
2021-06-06 21:14:05 +00:00
setIsListOrdered ( true )
setOrderedList ( result )
2021-09-22 20:24:31 +00:00
return true
} else {
return false
2021-06-06 21:14:05 +00:00
}
}
2021-11-25 11:58:50 +00:00
let nextStepSlider = ( { posList , binaryComparisons , sliderValue , Reasoning , element1 , element2 } ) => {
2021-11-25 09:01:31 +00:00
if ( sliderValue < 1 && sliderValue > 0 ) {
sliderValue = 1 / sliderValue ;
[ element1 , element2 ] = [ element2 , element1 ]
2021-06-06 22:18:40 +00:00
}
2021-06-12 14:13:13 +00:00
console . log ( ` posList@nextStepSlider: ` )
console . log ( posList )
2021-09-22 20:24:31 +00:00
let successStatus = nextStepSimple ( posList , binaryComparisons , element1 , element2 )
2021-06-06 22:18:40 +00:00
2021-11-25 11:58:50 +00:00
let newQuantitativeComparison = [ element1 , element2 , transformSliderValueToActualValue ( sliderValue ) , reasoning ]
2021-06-06 22:18:40 +00:00
let newQuantitativeComparisons = [ ... quantitativeComparisons , newQuantitativeComparison ]
setQuantitativeComparisons ( newQuantitativeComparisons )
2021-11-25 00:42:34 +00:00
setSliderValue ( 1 )
2021-11-25 11:58:50 +00:00
setReasoning ( '' )
2021-09-22 20:24:31 +00:00
if ( successStatus ) {
let jsObject = nicelyFormatLinks ( quantitativeComparisons , listOfElements )
pushToMongo ( jsObject )
2021-09-22 20:59:06 +00:00
console . log ( jsObject )
2021-09-22 20:24:31 +00:00
}
2021-06-06 22:18:40 +00:00
}
2021-06-06 21:14:05 +00:00
// Html
return (
2021-06-12 14:13:13 +00:00
< div className = "flex flex-col items-center justify-center min-h-screen py-2" >
< div className = "mt-20" >
< Head >
< title > Utility Function Extractor < / t i t l e >
< link rel = "icon" href = "/favicon.ico" / >
< / H e a d >
< / d i v >
2021-06-06 21:14:05 +00:00
2021-06-12 14:13:13 +00:00
< main className = "flex flex-col items-center w-full flex-1 px-20 text-center" >
2021-06-06 21:14:05 +00:00
< h1 className = "text-6xl font-bold" >
2021-09-22 19:45:18 +00:00
Utility Function Extractor
2021-06-06 21:14:05 +00:00
< / h 1 >
2021-09-22 19:45:18 +00:00
< div className = { ` ${ isListOrdered ? "hidden" : "" } ` } >
2021-06-12 14:13:13 +00:00
< div className = "flex flex-wrap items-center max-w-4xl sm:w-full mt-10" >
2021-09-22 19:45:18 +00:00
< div
className = "flex m-auto border-gray-300 border-4 h-72 w-72 p-5"
//onClick={() => nextStep(binaryComparisons, toComparePair[0], toComparePair[1])}
>
< div className = "block m-auto text-center" >
< DisplayElement element = { listOfElements [ toComparePair [ 0 ] ] } >
< / D i s p l a y E l e m e n t >
2021-06-06 22:18:40 +00:00
< / d i v >
2021-09-22 19:45:18 +00:00
< / d i v >
2021-11-25 00:42:34 +00:00
< div className = "flex m-auto w-72" >
< div className = "block m-auto text-center" >
{ /*`is ${displayFunctionSliderInner(sliderValue)}x times as valuable as`*/ }
< br / >
< label >
{ ` ... is ` }
< br / >
< input
type = "number"
value = { sliderValue }
onChange = { ( event ) => {
//console.log(event)
//console.log(event.target.value)
setSliderValue ( event . target . value )
} }
className = "text-center"
/ >
< br / >
{ ` times as valuable as ... ` }
< / l a b e l >
< br / >
2021-11-25 11:58:50 +00:00
< br / >
< label >
Reasoning :
< textarea value = { reasoning } onChange = { ( event ) => setReasoning ( event . target . value ) } / >
< / l a b e l >
< br / >
2021-11-25 00:42:34 +00:00
< SubmitSliderButton
posList = { posList }
binaryComparisons = { binaryComparisons }
sliderValue = { sliderValue }
2021-11-25 11:58:50 +00:00
reasoning = { reasoning }
2021-11-25 00:42:34 +00:00
toComparePair = { toComparePair }
nextStepSlider = { nextStepSlider }
/ >
< / d i v >
< / d i v >
2021-09-22 19:45:18 +00:00
< div
2021-11-25 00:42:34 +00:00
className = "flex m-auto border-gray-300 border-4 h-72 w-72 p-5 "
2021-09-22 19:45:18 +00:00
//onClick={() => nextStep(binaryComparisons, toComparePair[1], toComparePair[0])}
>
< div className = "block m-auto text-center" >
< DisplayElement element = { listOfElements [ toComparePair [ 1 ] ] } >
< / D i s p l a y E l e m e n t >
2021-06-06 22:18:40 +00:00
< / d i v >
2021-09-22 19:45:18 +00:00
< / d i v >
2021-06-06 22:18:40 +00:00
< / d i v >
2021-11-25 00:42:34 +00:00
< div >
< / d i v >
{ / *
2021-09-22 19:45:18 +00:00
< div className = { ` flex row-start-3 row-end-3 col-start-1 col-end-4 md:col-start-3 md:col-end-3 md:row-start-1 md:row-end-1 lg:col-start-3 lg:col-end-3 lg:row-start-1 lg:row-end-1 items-center justify-center mb-4 mt-10 ${ isListOrdered ? "hidden" : "" } ` } >
2021-06-06 22:18:40 +00:00
< SliderElement
2021-09-22 19:45:18 +00:00
className = "flex items-center justify-center"
onChange = { ( event ) => ( setSliderValue ( event [ 0 ] ) ) }
value = { sliderValue }
displayFunction = { displayFunctionSlider }
2021-10-06 11:00:09 +00:00
domain = { domain }
2021-09-22 19:45:18 +00:00
/ >
2021-06-06 22:18:40 +00:00
< / d i v >
2021-11-25 00:42:34 +00:00
* / }
2021-09-22 19:45:18 +00:00
2021-06-06 21:14:05 +00:00
< / d i v >
2021-09-22 19:45:18 +00:00
< DrawGraph
2021-06-07 08:41:43 +00:00
isListOrdered = { isListOrdered }
2021-06-12 14:13:13 +00:00
orderedList = { orderedList }
listOfElements = { listOfElements }
2021-06-10 21:52:33 +00:00
links = { buildLinks ( quantitativeComparisons ) } >
2021-06-07 08:41:43 +00:00
< / D r a w G r a p h >
2021-09-22 19:45:18 +00:00
< div className = { ` inline items-center text-center mt-10 ${ isListOrdered ? "" : "hidden" } ` } >
< CreateTableWithDistances
isListOrdered = { isListOrdered }
orderedList = { orderedList }
listOfElements = { listOfElements }
links = { buildLinks ( quantitativeComparisons ) }
>
< / C r e a t e T a b l e W i t h D i s t a n c e s >
2021-06-07 17:09:30 +00:00
< / d i v >
2021-06-12 14:13:13 +00:00
< div className = "w-2/12 flex justify-center mt-10" >
< button
className = "text-gray-500 text-sm"
onClick = { ( ) => changeShowAdvanceOptions ( ! showAdvancedOptions ) }
>
Advanced options ▼
< / b u t t o n >
< / d i v >
2021-09-22 19:45:18 +00:00
< div className = { ` flex flex-wrap -mx-4 overflow-hidden ${ showAdvancedOptions ? "" : "hidden" } ` } >
2021-06-12 14:13:13 +00:00
< div className = "my-4 px-4 w-1/3 overflow-hidden" >
2021-09-22 19:45:18 +00:00
< button
2021-06-12 14:13:13 +00:00
className = "bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick = { ( ) => restart ( posList ) } >
2021-09-22 19:45:18 +00:00
Restart
2021-06-12 14:13:13 +00:00
< / b u t t o n >
< / d i v >
< div className = "my-4 px-4 w-1/3 overflow-hidden" >
2021-09-22 19:45:18 +00:00
< button
2021-06-12 14:13:13 +00:00
className = "bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick = { ( ) => changeShowComparisons ( ! showComparisons ) } >
2021-09-22 19:45:18 +00:00
Show comparisons
2021-06-12 14:13:13 +00:00
< / b u t t o n >
< / d i v >
< div className = "my-4 px-4 w-1/3 overflow-hidden" >
2021-09-22 19:45:18 +00:00
< button
2021-06-12 14:13:13 +00:00
className = "bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick = { ( ) => changeshowChangeDataSet ( ! showChangeDataSet ) } >
2021-09-22 19:45:18 +00:00
Use your own data
2021-06-12 14:13:13 +00:00
< / b u t t o n >
< / d i v >
< / d i v >
2021-09-22 19:45:18 +00:00
< div className = { ` inline mt-5 ${ showChangeDataSet ? "" : "hidden" } ` } >
< TextAreaForJson handleSubmit = { changeDataSet } / >
2021-06-12 14:13:13 +00:00
< / d i v >
2021-09-22 19:45:18 +00:00
< div className = { ` inline mt-5 ${ showComparisons ? "" : "hidden" } ` } >
2021-06-12 14:13:13 +00:00
{ / *
< DisplayAsMarkdown markdowntext = { "## Ordered list\n\n" + JSON . stringify ( orderedList . map ( i => listOfElements [ i ] ) , null , 4 ) } > < / D i s p l a y A s M a r k d o w n >
* / }
< h2 > Comparisons < / h 2 >
< div className = "text-left" >
2021-09-22 19:45:18 +00:00
< DisplayAsMarkdown
2021-06-12 14:13:13 +00:00
markdowntext = { JSON . stringify ( nicelyFormatLinks ( quantitativeComparisons , listOfElements ) , null , 4 ) }
className = { "" } >
< / D i s p l a y A s M a r k d o w n >
< / d i v >
2021-06-07 14:01:15 +00:00
{ / *
< p > { ` Binary comparisons: ${ JSON . stringify ( binaryComparisons , null , 4 ) } ` } < / p >
2021-06-06 22:18:40 +00:00
< p > { ` Quantitative comparisons: ${ JSON . stringify ( quantitativeComparisons , null , 4 ) } ` } < / p >
2021-06-07 14:01:15 +00:00
* / }
2021-06-12 14:13:13 +00:00
< / d i v >
< / m a i n >
2021-06-06 21:14:05 +00:00
< / d i v >
)
}