From ddba3a13fe92f860fa5e78fa9e51f7038167eeba Mon Sep 17 00:00:00 2001 From: Paul Ford Date: Fri, 8 May 2020 10:12:32 -0400 Subject: [PATCH 1/5] fixup! feat: better formula for compound interest --- src/Section.css | 1 + src/smarter-text.js | 8 +++----- src/texts/pop.txt | 6 ++++++ 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 src/texts/pop.txt diff --git a/src/Section.css b/src/Section.css index b68025a..c475441 100644 --- a/src/Section.css +++ b/src/Section.css @@ -14,3 +14,4 @@ h1 { .negative { color:red; } + diff --git a/src/smarter-text.js b/src/smarter-text.js index 2b7869d..d45ea98 100644 --- a/src/smarter-text.js +++ b/src/smarter-text.js @@ -1,8 +1,6 @@ const P = require("parsimmon"); - -// const nerdamer = require('nerdamer/all'); -var ExpressionParser = require("expr-eval").Parser; -var Exp = new ExpressionParser(); +const ExpressionParser = require("expr-eval").Parser; +const Exp = new ExpressionParser(); const numeral = require("numeral"); /* @@ -15,7 +13,7 @@ expr-eval. let text = "If you had {10:apples_owned} and you gave me {0-10:apples_given}, you would have {=apples_owned - apples_given:apples_left}."; -let ast = docParser.Doc.tryParse(text); +let ast = docParser.Doc.tryParse(Text); // Which would give you ast back as... [ diff --git a/src/texts/pop.txt b/src/texts/pop.txt new file mode 100644 index 0000000..6b48e81 --- /dev/null +++ b/src/texts/pop.txt @@ -0,0 +1,6 @@ +The population in 1997 was +{5850000000:pop}. +In {1000:years} years ({=1997+years:year}AD) +human population will increase to +{=rate=0.0136;pop * E^(rate*years):future_pop} + From 8f6c59cb69e554ce015fb215d6c26291f5d10c03 Mon Sep 17 00:00:00 2001 From: Paul Ford Date: Sat, 9 May 2020 10:25:32 -0400 Subject: [PATCH 2/5] feat: charting using nivo linechart --- package.json | 4 +- src/App.js | 7 +- src/LineChart.js | 34 ++++ src/Nav.css | 2 +- src/Section.css | 3 + src/Section.js | 38 +++- src/smarter-text.js | 76 ++++++-- src/texts/pop.txt | 7 +- src/texts/soda.txt | 16 +- yarn.lock | 462 +++++++++++++++++++++++++++++++++++++++++++- 10 files changed, 599 insertions(+), 50 deletions(-) create mode 100644 src/LineChart.js diff --git a/package.json b/package.json index ed5b70c..c3e9f07 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.3.0", "private": true, "dependencies": { + "@nivo/line": "^0.61.1", "@postlight/use-search-params": "https://github.com/postlight/use-search-params.git", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", @@ -17,7 +18,8 @@ "react-emoji-render": "^1.2.2", "react-hamburger-menu": "^1.2.1", "react-router-dom": "^5.1.2", - "react-scripts": "3.4.1" + "react-scripts": "3.4.1", + "recharts": "^1.8.5" }, "scripts": { "start": "react-scripts start", diff --git a/src/App.js b/src/App.js index 1219e1e..78647dd 100644 --- a/src/App.js +++ b/src/App.js @@ -37,11 +37,12 @@ const textVars = textFiles.reduce( function App(props) { let { page } = useParams(); - const [ast, astState] = textVars[page]; + const [ast, astState, ranges] = textVars[page]; + console.log(ranges); return (
-
); } diff --git a/src/LineChart.js b/src/LineChart.js new file mode 100644 index 0000000..9e68b45 --- /dev/null +++ b/src/LineChart.js @@ -0,0 +1,34 @@ +import React from "react"; +import { ResponsiveLine } from '@nivo/line' + +function LineChart(props) +{ + return ( + + ) + + } + + +export default LineChart; diff --git a/src/Nav.css b/src/Nav.css index da03389..46e08b2 100644 --- a/src/Nav.css +++ b/src/Nav.css @@ -1,6 +1,7 @@ .burger { margin-left:-10px; position:fixed; + top:0; } #nav { @@ -26,7 +27,6 @@ div#nav.hamburger-true { transition:left 0.2s; } div#nav.hamburger-false { - visibility:none; } diff --git a/src/Section.css b/src/Section.css index c475441..b41fbca 100644 --- a/src/Section.css +++ b/src/Section.css @@ -15,3 +15,6 @@ h1 { color:red; } +div.spacer { + height:0.75em; +} diff --git a/src/Section.js b/src/Section.js index 7dab342..199ab75 100644 --- a/src/Section.js +++ b/src/Section.js @@ -5,14 +5,17 @@ import React, { useMemo } from "react"; import Slider from "./Slider"; import Statement from "./Statement"; import Text from "./Text"; +import LineChart from './LineChart'; + import "./Section.css"; function Section(props) { - const { ast, astState } = props; + const { ast, astState, ranges } = props; const searchParams = useSearchParams("replace"); const state = useMemo(readFields, [astState, searchParams]); + function addField(k, v) { searchParams.set(k, v); return v; @@ -27,7 +30,38 @@ function Section(props) { } function toComponents(o, i) { - switch (o.type) { + switch (o.type) { + + case "chart": + const range = ranges[o.x].range; + const exp = ranges[o.y]; + let s = Object.assign(state); + const inner_data = range.map( + (val,i)=>{ + s[o.x] = val; + + Object.keys(ranges).forEach(x=>{ + if (ranges[x].type==='expression') { + s[x] = ranges[x].eval(s); + } + }) + const y = exp.eval(s); + return ({x:val, y:y}) + } + ); + + const data = [{ + id:o.y, + data:inner_data + }]; + + return
+ +
+ case "paragraph": + return
+ case "text": return ; diff --git a/src/smarter-text.js b/src/smarter-text.js index d45ea98..77f9075 100644 --- a/src/smarter-text.js +++ b/src/smarter-text.js @@ -53,6 +53,7 @@ function explainDecimal(d) { } // Same as above, but we don't know value yet + function makeExpression(parseResult, kind) { const [expression, variable] = parseResult; return { @@ -90,7 +91,11 @@ const docParser = P.createLanguage({ // that; it wants hierarchy. Without that, the parser fails and // says (most often) that it was expecting EOF. - Doc: (r) => P.alt(r.DecimalExpression, r.Statement, r.Text).many(), + Doc: (r) => P.alt(r.DecimalExpression, + r.ChartExpression, + r.Statement, + r.Paragraph, + r.Text).many(), Statement: (r) => P.alt(r.DollarStatement, r.PercentageStatement, r.DecimalStatement), @@ -115,29 +120,35 @@ const docParser = P.createLanguage({ makeExpression(x, "dollar") ), - PercentageExpression: (r) => + PercentageExpression: (r) => P.seq(r.DecimalExpression, P.string("%")).map((x) => makeExpression(x, "percentage") ), - DecimalExpression: (r) => - r.PlainExpression.map((x) => makeExpression(x, "decimal")), - - PlainExpression: (r) => P.string("{=").then(r.MathPair).skip(P.string("}")), - - Pair: (r) => P.seq(r.Range.skip(P.string(":")), r.Variable), - - MathPair: (r) => P.seq(r.Math.skip(P.string(":")), r.Variable), - - Range: (r) => P.sepBy1(r.Decimal, P.string("-")).map(makeRange), - - Variable: (r) => P.regexp(/[a-z_]+/), - - Math: (r) => P.regexp(/[^:]+/), - - Decimal: (r) => P.regexp(/[+-]?[0-9.]+/).map(explainDecimal), - - Text: (r) => + DecimalExpression: (r) => r.PlainExpression.map((x) => makeExpression(x, "decimal")), + + PlainExpression: (r) => P.string("{=").then(r.MathPair).skip(P.string("}")), + + ChartExpression: (r) => P.string("{#").then(r.ChartPair).skip(P.string("}")).map(x=>({type:"chart", y:x[0], x:x[1]})), + + Pair: (r) => P.seq(r.Range.skip(P.string(":")), r.Variable), + + MathPair: (r) => P.seq(r.Math.skip(P.string(":")), r.Variable), + + Range: (r) => P.sepBy1(r.Decimal, P.string("-")).map(makeRange), + + ChartPair: (r) => P.sepBy1(r.Variable, P.string(" by ")), + + Variable: (r) => P.regexp(/[a-z_]+/), + + Math: (r) => P.regexp(/[^:]+/), + + Decimal: (r) => P.regexp(/[+-]?[0-9.]+/).map(explainDecimal), + + Paragraph: (r) => P.newline.times(2).map(x=>({type: "paragraph"})), + + Text: (r) => + P.alt(P.any, P.whitespace).map((x) => ({ type: "text", value: x })), }); @@ -157,6 +168,7 @@ function parse(text) { return arr.concat(el); }, []); + let state = concatted.reduce(function (obj, value) { if (value.type === "statement") { Object.assign(obj, { [value.variable]: value.value.value }); @@ -166,12 +178,34 @@ function parse(text) { return obj; }, {}); + + let ranges = concatted.reduce(function (obj, value) { + let vv = value.value; + + if (value.type === "statement") { + const ARRAY_SIZE = 10; + let arr = []; + const tick = (vv.max - vv.min)/ARRAY_SIZE; + for (let i = vv.min; i <= vv.max; i = i + tick) { + arr.push(i); + } + vv['range'] = arr; + Object.assign(obj, { [value.variable]: vv }); + } + else if (value.type === "expression") { + Object.assign(obj, { [value.variable]: value }); + } + return obj; + }, {}); + + const mathed = concatted.filter((o) => o.type === "expression"); mathed.map((el) => { state[el.variable] = el.eval(state); return true; }); - return [concatted, state]; + + return [concatted, state, ranges]; } // var fs = require("fs"); diff --git a/src/texts/pop.txt b/src/texts/pop.txt index 6b48e81..0a2ef3c 100644 --- a/src/texts/pop.txt +++ b/src/texts/pop.txt @@ -1,6 +1,3 @@ -The population in 1997 was -{5850000000:pop}. -In {1000:years} years ({=1997+years:year}AD) -human population will increase to -{=rate=0.0136;pop * E^(rate*years):future_pop} +Population. The population in 1997 was {5.85:pop} billion. The rate of population growth is {1.36:rate}%. In {100:years} years ({=1997+years:year}AD) human population will increase to {=pop * E^((rate/100)*years):future_pop} billion people. +{#future_pop by years} diff --git a/src/texts/soda.txt b/src/texts/soda.txt index 2e3b921..cdc8b10 100644 --- a/src/texts/soda.txt +++ b/src/texts/soda.txt @@ -1,13 +1,15 @@ :cup_with_straw: You drink {1-4:sodas_daily} Diet Cokes per day, at a cost of ${0.00-3.50:soda_cost} per Diet Coke. (${=sodas_daily * soda_cost * 365.25/12:monthly} a month). If you'd put that into a fund with a {6.00:rate}% annual rate, you'd have ${= - t = 12; - period = 10 * t; - i = rate/100; - f() = (i>0.0000001); - interest = if(f(i),i,0.0000001); - adjusted = interest/t; - monthly * ((((1 + adjusted)^period) - 1) / adjusted) +t = 12; +period = 10 * t; +i = rate/100; +f() = (i>0.0000001); +interest = if(f(i),i,0.0000001); +adjusted = interest/t; + +monthly * ((((1 + adjusted)^period) - 1) / adjusted) :total} in a decade. +{#total by soda_cost} diff --git a/yarn.lock b/yarn.lock index 09c0263..92e6bdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -988,7 +988,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.9.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== @@ -1244,6 +1244,113 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" +"@nivo/annotations@0.61.0": + version "0.61.0" + resolved "https://registry.yarnpkg.com/@nivo/annotations/-/annotations-0.61.0.tgz#f09fc99f018e0d0c39f01ed9447e1a2cc0c5e6df" + integrity sha512-i2JKYeMEPC+zwgN/p+hVRWUJ4aee+kE8BfMzCLt1/a+rsfT+v2v5kj12zx072teoaQt53lOi1GdV2lEYA6HJpg== + dependencies: + "@nivo/colors" "0.61.0" + "@nivo/core" "0.61.0" + lodash "^4.17.11" + react-motion "^0.5.2" + +"@nivo/axes@0.61.0": + version "0.61.0" + resolved "https://registry.yarnpkg.com/@nivo/axes/-/axes-0.61.0.tgz#f22852b56f02d99867eb27fa3be349a75f749cbb" + integrity sha512-U0rHIYNnwt03dFFBz0aosfd5nFIRVD1Wff5DwVeM7PouBZM3AsLVWeLlUWLWOmg+BHftqhbOGTOoZN2SjU7bwA== + dependencies: + "@nivo/core" "0.61.0" + d3-format "^1.3.2" + d3-time "^1.0.11" + d3-time-format "^2.1.3" + lodash "^4.17.11" + react-motion "^0.5.2" + +"@nivo/colors@0.61.0": + version "0.61.0" + resolved "https://registry.yarnpkg.com/@nivo/colors/-/colors-0.61.0.tgz#5af2a6d8b1d22c786950cc9fb07c216a80a541ff" + integrity sha512-yeb5YsQDoN7D5DbBIhHTnVn0bX+4ObNVGyJAepSn64zNPiskO3/o1FnQw70aIkN4O7BDXb/vVPrftq6wSwQtvQ== + dependencies: + d3-color "^1.2.3" + d3-scale "^3.0.0" + d3-scale-chromatic "^1.3.3" + lodash.get "^4.4.2" + lodash.isplainobject "^4.0.6" + react-motion "^0.5.2" + +"@nivo/core@0.61.0": + version "0.61.0" + resolved "https://registry.yarnpkg.com/@nivo/core/-/core-0.61.0.tgz#66581a0e2dc4f8f802bd0f1515f1f2269b0595e0" + integrity sha512-7DGsTW12vfUvMIr9jl28KZaJMJqMMhEJi1lW1R2TPMTg+qSG01v6tqMtcEwUp4bdAdr3n57ytLWSgqKWXkwjvw== + dependencies: + "@nivo/tooltip" "0.61.0" + d3-color "^1.2.3" + d3-format "^1.3.2" + d3-hierarchy "^1.1.8" + d3-interpolate "^1.3.2" + d3-scale "^3.0.0" + d3-scale-chromatic "^1.3.3" + d3-shape "^1.3.5" + d3-time-format "^2.1.3" + lodash "^4.17.11" + react-measure "^2.2.4" + react-motion "^0.5.2" + recompose "^0.30.0" + +"@nivo/legends@0.61.1": + version "0.61.1" + resolved "https://registry.yarnpkg.com/@nivo/legends/-/legends-0.61.1.tgz#54ac123b25449e7663067b3e019c7d3a9429a6f9" + integrity sha512-bKVXffFwTKGySZRUf6sdVzWUb5jjGffuvRczs0giQCu8OUgeJIi0IOOyYhHtww+rTVGIKAi0xPGQTQnF4kpufA== + dependencies: + "@nivo/core" "0.61.0" + lodash "^4.17.11" + recompose "^0.30.0" + +"@nivo/line@^0.61.1": + version "0.61.1" + resolved "https://registry.yarnpkg.com/@nivo/line/-/line-0.61.1.tgz#7e857c4abababef3e019211deff9feb347cec788" + integrity sha512-PZFGgcj+IlDtZG6kTdBrGJ5cJvs1w5kaAI86IaH5AXJ0MQqVIZYWgbXdf5Vg6Hv2ouLmwNwONA/ORACKVkG+YA== + dependencies: + "@nivo/annotations" "0.61.0" + "@nivo/axes" "0.61.0" + "@nivo/colors" "0.61.0" + "@nivo/core" "0.61.0" + "@nivo/legends" "0.61.1" + "@nivo/scales" "0.61.0" + "@nivo/tooltip" "0.61.0" + "@nivo/voronoi" "0.61.0" + d3-shape "^1.3.5" + lodash "^4.17.11" + react-motion "^0.5.2" + +"@nivo/scales@0.61.0": + version "0.61.0" + resolved "https://registry.yarnpkg.com/@nivo/scales/-/scales-0.61.0.tgz#48bcc94941271f1f23c353f1da1ee4da1af981ef" + integrity sha512-7MoxxecMDvpK9L0Py/drEQxG/4YAzo9KBvLzo3/KjInc1VEscpDkpVSSN5tmg1qbQE3WCrziec4JuH9q1V/Q7g== + dependencies: + d3-scale "^3.0.0" + d3-time-format "^2.1.3" + lodash "^4.17.11" + +"@nivo/tooltip@0.61.0": + version "0.61.0" + resolved "https://registry.yarnpkg.com/@nivo/tooltip/-/tooltip-0.61.0.tgz#bf8b06a18f41fc9072e3f2d9591ebbb9b45c2a54" + integrity sha512-CqEJ4v1jSikZ3fmuSJVb1UYF8fuCo/c7JFB+LsNH9X01IERSufO3tSNBTzJ3JugCminQpbo6/R7oBhNwZFqSxw== + dependencies: + "@nivo/core" "0.61.0" + react-measure "^2.2.4" + react-motion "^0.5.2" + +"@nivo/voronoi@0.61.0": + version "0.61.0" + resolved "https://registry.yarnpkg.com/@nivo/voronoi/-/voronoi-0.61.0.tgz#977da00f7805d57f4d315116785503c611570ef5" + integrity sha512-VVB7BW8GX8Gq9kTf/L52HrCD//4PAT6RTeDwb4N8BpSNfyfmBXacU9U9RMK7HAJjxICzEuxam75/oTCjX6iVBg== + dependencies: + "@nivo/core" "0.61.0" + d3-delaunay "^5.1.1" + d3-scale "^3.0.0" + recompose "^0.30.0" + "@nodelib/fs.stat@^1.1.2": version "1.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" @@ -2046,7 +2153,7 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asap@~2.0.6: +asap@~2.0.3, asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -2307,6 +2414,11 @@ babylon@^6.18.0: resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== +balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + integrity sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg= + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -2747,6 +2859,11 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +change-emitter@^0.1.2: + version "0.1.6" + resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" + integrity sha1-6LL+PX8at9aaMhma/5HqaTFAlRU= + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -3118,7 +3235,12 @@ core-js-pure@^3.0.0: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== -core-js@^2.4.0: +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= + +core-js@^2.4.0, core-js@^2.6.10: version "2.6.11" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== @@ -3453,6 +3575,105 @@ cyclist@^1.0.1: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= +"d3-array@1.2.0 - 2": + version "2.4.0" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.4.0.tgz#87f8b9ad11088769c82b5ea846bcb1cc9393f242" + integrity sha512-KQ41bAF2BMakf/HdKT865ALd4cgND6VcIztVQZUTt0+BH3RWy6ZYnHghVXf6NFjt2ritLr8H1T8LreAAlfiNcw== + +d3-array@^1.2.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" + integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== + +d3-collection@1: + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e" + integrity sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A== + +d3-color@1, d3-color@^1.2.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" + integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== + +d3-delaunay@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-5.2.1.tgz#0c4b280eb00194986ac4a3df9c81d32bf216cb36" + integrity sha512-ZZdeJl6cKRyqYVFYK+/meXvWIrAvZsZTD7WSxl4OPXCmuXNgDyACAClAJHD63zL25TA+IJGURUNO7rFseNFCYw== + dependencies: + delaunator "4" + +d3-format@1, d3-format@^1.3.2: + version "1.4.4" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.4.tgz#356925f28d0fd7c7983bfad593726fce46844030" + integrity sha512-TWks25e7t8/cqctxCmxpUuzZN11QxIA7YrMbram94zMQ0PXjE4LVIMe/f6a4+xxL8HQ3OsAFULOINQi1pE62Aw== + +d3-hierarchy@^1.1.8: + version "1.1.9" + resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83" + integrity sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ== + +d3-interpolate@1, d3-interpolate@^1.2.0, d3-interpolate@^1.3.0, d3-interpolate@^1.3.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987" + integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA== + dependencies: + d3-color "1" + +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-scale-chromatic@^1.3.3: + version "1.5.0" + resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz#54e333fc78212f439b14641fb55801dd81135a98" + integrity sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg== + dependencies: + d3-color "1" + d3-interpolate "1" + +d3-scale@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f" + integrity sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw== + dependencies: + d3-array "^1.2.0" + d3-collection "1" + d3-format "1" + d3-interpolate "1" + d3-time "1" + d3-time-format "2" + +d3-scale@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.2.1.tgz#da1684adce7261b4bc7a76fe193d887f0e909e69" + integrity sha512-huz5byJO/6MPpz6Q8d4lg7GgSpTjIZW/l+1MQkzKfu2u8P6hjaXaStOpmyrD6ymKoW87d2QVFCKvSjLwjzx/rA== + dependencies: + d3-array "1.2.0 - 2" + d3-format "1" + d3-interpolate "^1.2.0" + d3-time "1" + d3-time-format "2" + +d3-shape@^1.2.0, d3-shape@^1.3.5: + version "1.3.7" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" + integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== + dependencies: + d3-path "1" + +d3-time-format@2, d3-time-format@^2.1.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.2.3.tgz#0c9a12ee28342b2037e5ea1cf0b9eb4dd75f29cb" + integrity sha512-RAHNnD8+XvC4Zc4d2A56Uw0yJoM7bsvOlJR33bclxq399Rak/b9bhvu/InjxdWhPtkgU53JJcleJTGkNRnN6IA== + dependencies: + d3-time "1" + +d3-time@1, 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== + d@1, d@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" @@ -3508,6 +3729,11 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decimal.js-light@^2.4.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.0.tgz#ca7faf504c799326df94b0ab920424fdfc125348" + integrity sha512-b3VJCbd2hwUpeRGG3Toob+CRo8W22xplipNhP3tN7TSVB/cyMX71P1vM2Xjc9H74uV6dS2hDDmo/rHq8L87Upg== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -3580,6 +3806,11 @@ del@^4.1.1: pify "^4.0.1" rimraf "^2.6.3" +delaunator@4: + version "4.0.1" + resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-4.0.1.tgz#3d779687f57919a7a418f8ab947d3bddb6846957" + integrity sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag== + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -3697,6 +3928,13 @@ dom-converter@^0.2: dependencies: utila "~0.4" +dom-helpers@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8" + integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== + dependencies: + "@babel/runtime" "^7.1.2" + dom-serializer@0: version "0.2.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" @@ -3851,6 +4089,13 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -4415,6 +4660,19 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fbjs@^0.8.1: + version "0.8.17" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" + integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + figgy-pudding@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" @@ -4735,6 +4993,11 @@ get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-node-dimensions@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz#fb7b4bb57060fb4247dd51c9d690dfbec56b0823" + integrity sha512-2MSPMu7S1iOTL+BOa6K1S62hB2zUAYNF/lV0gSVlOaacd087lc6nR1H1r0e3B1CerTo+RceOmi1iJW+vp21xcQ== + get-own-enumerable-property-symbols@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" @@ -4997,6 +5260,11 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^2.3.1: + version "2.5.5" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" + integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== + hoist-non-react-statics@^3.1.0: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -5163,7 +5431,7 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -5634,7 +5902,7 @@ is-root@2.1.0: resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== -is-stream@^1.1.0: +is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -5707,6 +5975,14 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -6506,11 +6782,26 @@ lodash._reinterpolate@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + lodash.flatten@^4.2.0, lodash.flatten@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + lodash.isstring@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" @@ -6541,12 +6832,17 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5: +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@~4.17.4: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -6623,6 +6919,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +math-expression-evaluator@^1.2.14: + version "1.2.22" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.22.tgz#c14dcb3d8b4d150e5dcea9c68c8dad80309b0d5e" + integrity sha512-L0j0tFVZBQQLeEjmWOvDLoRciIY8gQGWahvkztXUal8jH8R5Rlqo9GCvgqvXcy9LQhEWdQCVvzqAbxgYNt4blQ== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -6973,6 +7274,14 @@ no-case@^3.0.3: lower-case "^2.0.1" tslib "^1.10.0" +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-forge@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" @@ -7594,6 +7903,11 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + integrity sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU= + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -8440,6 +8754,13 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + promise@^8.0.3: version "8.1.0" resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e" @@ -8455,7 +8776,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.4" -prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -8572,7 +8893,7 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== -raf@^3.4.1: +raf@^3.1.0, raf@^3.4.0, raf@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -8695,6 +9016,40 @@ react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-i resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-measure@^2.2.4: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-2.3.0.tgz#75835d39abec9ae13517f35a819c160997a7a44e" + integrity sha512-dwAvmiOeblj5Dvpnk8Jm7Q8B4THF/f1l1HtKVi0XDecsG6LXwGvzV5R1H32kq3TW6RW64OAf5aoQxpIgLa4z8A== + dependencies: + "@babel/runtime" "^7.2.0" + get-node-dimensions "^1.2.1" + prop-types "^15.6.2" + resize-observer-polyfill "^1.5.0" + +react-motion@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.5.2.tgz#0dd3a69e411316567927917c6626551ba0607316" + integrity sha512-9q3YAvHoUiWlP3cK0v+w1N5Z23HXMj4IF4YuvjvWegWqNPfLXsOBE/V7UvQGpXxHFKRQQcNcVQE31g9SB/6qgQ== + dependencies: + performance-now "^0.2.0" + prop-types "^15.5.8" + raf "^3.1.0" + +react-resize-detector@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-2.3.0.tgz#57bad1ae26a28a62a2ddb678ba6ffdf8fa2b599c" + integrity sha512-oCAddEWWeFWYH5FAcHdBYcZjAw9fMzRUK9sWSx6WvSSOPVRxcHd5zTIGy/mOus+AhN/u6T4TMiWxvq79PywnJQ== + dependencies: + lodash.debounce "^4.0.8" + lodash.throttle "^4.1.1" + prop-types "^15.6.0" + resize-observer-polyfill "^1.5.0" + react-router-dom@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18" @@ -8784,6 +9139,26 @@ react-scripts@3.4.1: optionalDependencies: fsevents "2.1.2" +react-smooth@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-1.0.5.tgz#94ae161d7951cdd893ccb7099d031d342cb762ad" + integrity sha512-eW057HT0lFgCKh8ilr0y2JaH2YbNcuEdFpxyg7Gf/qDKk9hqGMyXryZJ8iMGJEuKH0+wxS0ccSsBBB3W8yCn8w== + dependencies: + lodash "~4.17.4" + prop-types "^15.6.0" + raf "^3.4.0" + react-transition-group "^2.5.0" + +react-transition-group@^2.5.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d" + integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg== + dependencies: + dom-helpers "^3.4.0" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react-lifecycles-compat "^3.0.4" + react@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" @@ -8872,6 +9247,42 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" +recharts-scale@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.3.tgz#040b4f638ed687a530357292ecac880578384b59" + integrity sha512-t8p5sccG9Blm7c1JQK/ak9O8o95WGhNXD7TXg/BW5bYbVlr6eCeRBNpgyigD4p6pSSMehC5nSvBUPj6F68rbFA== + dependencies: + decimal.js-light "^2.4.1" + +recharts@^1.8.5: + version "1.8.5" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-1.8.5.tgz#ca94a3395550946334a802e35004ceb2583fdb12" + integrity sha512-tM9mprJbXVEBxjM7zHsIy6Cc41oO/pVYqyAsOHLxlJrbNBuLs0PHB3iys2M+RqCF0//k8nJtZF6X6swSkWY3tg== + dependencies: + classnames "^2.2.5" + core-js "^2.6.10" + d3-interpolate "^1.3.0" + d3-scale "^2.1.0" + d3-shape "^1.2.0" + lodash "^4.17.5" + prop-types "^15.6.0" + react-resize-detector "^2.3.0" + react-smooth "^1.0.5" + recharts-scale "^0.4.2" + reduce-css-calc "^1.3.0" + +recompose@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0" + integrity sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w== + dependencies: + "@babel/runtime" "^7.0.0" + change-emitter "^0.1.2" + fbjs "^0.8.1" + hoist-non-react-statics "^2.3.1" + react-lifecycles-compat "^3.0.2" + symbol-observable "^1.0.4" + recursive-readdir@2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" @@ -8887,6 +9298,22 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +reduce-css-calc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + integrity sha1-dHyRTgSWFKTJz7umKYca0dKSdxY= + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-function-call@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.3.tgz#60350f7fb252c0a67eb10fd4694d16909971300f" + integrity sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ== + dependencies: + balanced-match "^1.0.0" + regenerate-unicode-properties@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" @@ -9065,6 +9492,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +resize-observer-polyfill@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -9393,7 +9825,7 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -10022,6 +10454,11 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-tree@^3.2.2: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -10294,6 +10731,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +ua-parser-js@^0.7.18: + version "0.7.21" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777" + integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ== + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -10690,7 +11132,7 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" -whatwg-fetch@^3.0.0: +whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== From 5e2f49d554a65e1230effac610694cca8c977f30 Mon Sep 17 00:00:00 2001 From: Paul Ford Date: Sun, 10 May 2020 14:14:32 -0400 Subject: [PATCH 3/5] feat: random number generator --- src/App.css | 29 ++++++++++++++- src/App.js | 1 - src/LineChart.js | 69 ++++++++++++++++++++-------------- src/Section.css | 13 +++++++ src/Section.js | 90 ++++++++++++++++++++++++++++++--------------- src/smarter-text.js | 44 ++++++++++++++++------ src/texts/blog.txt | 13 +++---- src/texts/pop.txt | 2 +- src/texts/soda.txt | 12 +++--- src/texts/vc.txt | 11 +++--- 10 files changed, 191 insertions(+), 93 deletions(-) diff --git a/src/App.css b/src/App.css index 7b7ebf4..843ab6c 100644 --- a/src/App.css +++ b/src/App.css @@ -3,8 +3,8 @@ body { font-size:1.5em; - line-height:2em; - font-family: 'IBM Plex Sans', sans-serif; + line-height:1.5em; + font-family: 'IBM Plex Serif', sans-serif; color:#444; } @@ -13,3 +13,28 @@ body { color:#222; } +button { + box-shadow:inset 0px 1px 0px 0px #ffffff; + background:linear-gradient(to bottom, #ededed 5%, #dfdfdf 100%); + background-color:#ededed; + border-radius:6px; + border:1px solid #dcdcdc; + display:inline-block; + cursor:pointer; + color:#777777; + font-family:IBM Plex Sans; + font-size:1em; + font-weight:bold; + text-decoration:none; + text-shadow:0px 1px 0px #ffffff; + margin-right:4px; +} + +button:hover { + background:linear-gradient(to bottom, #dfdfdf 5%, #ededed 100%); + background-color:#dfdfdf; +} + +button:active { + position:relative; +} diff --git a/src/App.js b/src/App.js index 78647dd..16cf7aa 100644 --- a/src/App.js +++ b/src/App.js @@ -38,7 +38,6 @@ const textVars = textFiles.reduce( function App(props) { let { page } = useParams(); const [ast, astState, ranges] = textVars[page]; - console.log(ranges); return (
diff --git a/src/LineChart.js b/src/LineChart.js index 9e68b45..f28c443 100644 --- a/src/LineChart.js +++ b/src/LineChart.js @@ -1,34 +1,47 @@ import React from "react"; import { ResponsiveLine } from '@nivo/line' -function LineChart(props) -{ - return ( - - ) - - } +function LineChart(props) { + return ( + + ) +} export default LineChart; diff --git a/src/Section.css b/src/Section.css index b41fbca..899ecd9 100644 --- a/src/Section.css +++ b/src/Section.css @@ -18,3 +18,16 @@ h1 { div.spacer { height:0.75em; } + +.chart { + height:325px; + border:1px solid #ccc; + padding:0px 50px 120px 1em; + background:#fafafa; +} + +.chart h3 { + font-weight:200; +} + + diff --git a/src/Section.js b/src/Section.js index 199ab75..0e446e2 100644 --- a/src/Section.js +++ b/src/Section.js @@ -12,11 +12,10 @@ import "./Section.css"; function Section(props) { const { ast, astState, ranges } = props; - const searchParams = useSearchParams("replace"); - const state = useMemo(readFields, [astState, searchParams]); + const searchParams = useSearchParams("replace"); + const state = useMemo(readFields, [astState, searchParams]); - - function addField(k, v) { + function addField(k, v) { searchParams.set(k, v); return v; } @@ -29,17 +28,17 @@ function Section(props) { ); } - function toComponents(o, i) { + function toComponents(o, i) { switch (o.type) { case "chart": const range = ranges[o.x].range; const exp = ranges[o.y]; let s = Object.assign(state); + const inner_data = range.map( (val,i)=>{ s[o.x] = val; - Object.keys(ranges).forEach(x=>{ if (ranges[x].type==='expression') { s[x] = ranges[x].eval(s); @@ -49,14 +48,30 @@ function Section(props) { return ({x:val, y:y}) } ); + const _minValue = inner_data[0].y; + const _maxValue = inner_data[inner_data.length - 1].y; + const [minValue, maxValue] = [_minValue, _maxValue].sort((a,b)=>a-b); const data = [{ id:o.y, data:inner_data }]; - - return
- + function c(x) { + return x.replace(/_/g, ' ').toUpperCase(); + + } + return
+

{c(o.y)} vs. {c(o.x)}

+ numeral(x).format('-0,0')} + yFormat={(x)=>{ + console.log('Y',x); + return numeral(x).format('-0,0')}} + minValue={minValue} + maxValue={maxValue} + xLabel={c(o.x)} + yLabel={c(o.y)}/>
case "paragraph": return
-10) { - return num.format("0.00"); + function format(n) { + const num = numeral(n); + if (n < 10 && n > -10) { + return num.format("0.00"); + } + return num.format("-0,0"); } - return num.format("-0,0"); - } - function evaluate(o) { - const n = o.eval(state); - state[o.variable] = n; - return n; - } - const n = evaluate(o); - const sign = n > 0 ? "positive" : "negative"; - return ( - - {format(n)} - - ); + function evaluate(o) { + const n = o.eval(state); + state[o.variable] = n; + return n; + } + function newNum() { + const n = o.eval(); + state[o.variable] = n; + addField(o.variable, n); + console.log(o.variable, n, state[o.variable]); + } + + const n = evaluate(o); + const sign = n > 0 ? "positive" : "negative"; + if (o.interactive) { + + return + + } + else { + return ( + + {format(n)} + + ); + } + default: - return undefined; - } - } + return undefined; + } + } return (
diff --git a/src/smarter-text.js b/src/smarter-text.js index 77f9075..cd013cb 100644 --- a/src/smarter-text.js +++ b/src/smarter-text.js @@ -1,6 +1,14 @@ const P = require("parsimmon"); const ExpressionParser = require("expr-eval").Parser; + + + + const Exp = new ExpressionParser(); +Exp.functions.text = function (txt) { + return ""+txt; +}; + const numeral = require("numeral"); /* @@ -57,7 +65,8 @@ function explainDecimal(d) { function makeExpression(parseResult, kind) { const [expression, variable] = parseResult; return { - type: "expression", + type:"expression", + interactive:kind==="interactive", format: kind, expression: expression, value: undefined, @@ -91,7 +100,8 @@ const docParser = P.createLanguage({ // that; it wants hierarchy. Without that, the parser fails and // says (most often) that it was expecting EOF. - Doc: (r) => P.alt(r.DecimalExpression, + Doc: (r) => P.alt(r.InteractiveExpression, + r.DecimalExpression, r.ChartExpression, r.Statement, r.Paragraph, @@ -115,8 +125,7 @@ const docParser = P.createLanguage({ makeStatement(x, "percentage") ), - DollarExpression: (r) => - P.seq(P.string("$"), r.DecimalExpression).map((x) => + DollarExpression: (r) => P.seq(P.string("$"), r.DecimalExpression).map((x) => makeExpression(x, "dollar") ), @@ -125,11 +134,15 @@ const docParser = P.createLanguage({ makeExpression(x, "percentage") ), + PlainExpression: (r) => P.string("{=").then(r.MathPair).skip(P.string("}")), + + DecimalExpression: (r) => r.PlainExpression.map((x) => makeExpression(x, "decimal")), - PlainExpression: (r) => P.string("{=").then(r.MathPair).skip(P.string("}")), ChartExpression: (r) => P.string("{#").then(r.ChartPair).skip(P.string("}")).map(x=>({type:"chart", y:x[0], x:x[1]})), + + InteractiveExpression: (r) => P.string("{!=").then(r.MathPair).skip(P.string("}")).map((x)=>makeExpression(x, "interactive")), Pair: (r) => P.seq(r.Range.skip(P.string(":")), r.Variable), @@ -170,11 +183,16 @@ function parse(text) { let state = concatted.reduce(function (obj, value) { - if (value.type === "statement") { - Object.assign(obj, { [value.variable]: value.value.value }); - } else if (value.type === "expression") { - Object.assign(obj, { [value.variable]: value.value }); - } + if (value.type === "interactive") { + console.log('INTERACTIVE', value); + Object.assign(obj, { [value.variable]: value.value }); + } + else if (value.type === "statement") { + Object.assign(obj, { [value.variable]: value.value.value }); + } + else if (value.type === "expression") { + Object.assign(obj, { [value.variable]: value.value }); + } return obj; }, {}); @@ -187,9 +205,11 @@ function parse(text) { let arr = []; const tick = (vv.max - vv.min)/ARRAY_SIZE; for (let i = vv.min; i <= vv.max; i = i + tick) { - arr.push(i); + const j = Math.round(i) + arr.push(j); } - vv['range'] = arr; + arr.sort((a,b)=>a-b); + vv['range'] = arr Object.assign(obj, { [value.variable]: vv }); } else if (value.type === "expression") { diff --git a/src/texts/blog.txt b/src/texts/blog.txt index c02d9da..52c6c25 100644 --- a/src/texts/blog.txt +++ b/src/texts/blog.txt @@ -1,12 +1,11 @@ -You are a publisher on the Internet. +You are a publisher on the Internet. You generate {40:posts} posts per day, for a total of {=posts * 365:annual_posts} posts a year. It costs ${1000:post_cost} to make a post, which means you spend ${=annual_posts * post_cost:annual_expenses} per year on content. -You generate {40:posts} posts per day, for a total of {=posts * 365:annual_posts} posts a year. It costs ${1000:post_cost} to make a post, which means you spend ${=annual_posts * post_cost:annual_expenses} per year on content. +Each post gets an average of {50000:views_per_post} readers, and they go on to look at around {3:recirculation} other pages. That yields {=(recirculation + 1) * (views_per_post * posts) * 30:pageviews} page views every 30 days (and as many as {=views_per_post * posts * 30:uniques} unique readers, although let's be honest). Anyone who visits is {3:repeat}% likely to visit again next month. -Each post gets an average of {50000:readers} readers, and they go on to look at around {3:recirculation} other pages. That yields {=(recirculation + 1) * (readers * posts) * 30:pageviews} page views every 30 days (and as many as {=readers * posts * 30:uniques} unique readers, although let's be honest). Anyone who visits is {3:repeat}% likely to visit again next month. +At a ${0.01-5.00:cpm} CPM (cost per mille), and with {4:placements} ad placements per page, that means you can make ${=((pageviews + (pageviews * (repeat/100)))/1000) * placements * cpm:revenue}/month, or ${=revenue * 12:annual_revenue} a year. -At a ${0.01-5.00:cpm} CPM (cost per mille), and with {4:placements} ad placements per page, that means you can make +This means that your annual profit is ${=annual_revenue - annual_expenses:profit}. -${=((pageviews + (pageviews * (repeat/100)))/1000) * placements * cpm:revenue}/month, -or ${=revenue * 12:annual_revenue} a year. +{#profit by views_per_post} -This means that your annual profit is ${=annual_revenue - annual_expenses:profit}. +{#profit by placements} diff --git a/src/texts/pop.txt b/src/texts/pop.txt index 0a2ef3c..62c9721 100644 --- a/src/texts/pop.txt +++ b/src/texts/pop.txt @@ -1,3 +1,3 @@ -Population. The population in 1997 was {5.85:pop} billion. The rate of population growth is {1.36:rate}%. In {100:years} years ({=1997+years:year}AD) human population will increase to {=pop * E^((rate/100)*years):future_pop} billion people. +Population. The population in 1997 was {5.85:pop} billion. The rate of population growth is {-1.36-1.36:rate}%. In {100:years} years ({=1997+years:year}AD) human population will increase to {=pop * E^((rate/100)*years):future_pop} billion people. {#future_pop by years} diff --git a/src/texts/soda.txt b/src/texts/soda.txt index cdc8b10..7f69d63 100644 --- a/src/texts/soda.txt +++ b/src/texts/soda.txt @@ -1,15 +1,15 @@ -:cup_with_straw: You drink {1-4:sodas_daily} Diet Cokes per day, at a cost of ${0.00-3.50:soda_cost} per Diet Coke. (${=sodas_daily * soda_cost * 365.25/12:monthly} a month). If you'd put that into a fund with a {6.00:rate}% annual rate, you'd have +:cup_with_straw: You drink {1-4:daily_sodas} Diet Cokes per day, at a cost of ${0.00-3.50:cost_per_soda} per Diet Coke. (${=daily_sodas * cost_per_soda * 365.25/12:monthly_costs} a month). If you'd put that into a fund with a {-6.00-6.00:fund_rate}% annual rate, you'd have ${= t = 12; period = 10 * t; -i = rate/100; -f() = (i>0.0000001); +i = fund_rate/100; +f() = (i>0.0000001 or i < 0); interest = if(f(i),i,0.0000001); adjusted = interest/t; -monthly * ((((1 + adjusted)^period) - 1) / adjusted) +monthly_costs * ((((1 + adjusted)^period) - 1) / adjusted) -:total} in a decade. +:total_saved} in a decade. -{#total by soda_cost} +{#total_saved by daily_sodas} diff --git a/src/texts/vc.txt b/src/texts/vc.txt index 6dc5944..5248e21 100644 --- a/src/texts/vc.txt +++ b/src/texts/vc.txt @@ -1,14 +1,13 @@ -You have a fund with ${20000000-1000000000:cash_out}. You make {0-200:investments} investments of ${=(cash_out / investments):individual_investment} each. - -{0-80:failure}% of those investments fail outright. {0-20:success}% achieve significant growth. That means that you lose your shirt on - +You have a fund with ${20-4000:cash_out} mm. You make {0-200:investments} investments of ${=(cash_out / investments):individual_investment} each. {!=round(random(100)):failure}% of those investments fail outright. {0-20:success}% achieve significant growth. That means that you lose your shirt on {=ceil(investments * (failure/100)):failures} companies, - don't lose money on {=ceil(investments * (100 - failure - success)/100):averages} investments - and achieve breakout growth on {=floor(investments * (success/100)):successes} investments. When you take an average of the successful ones you find that your investment in only those firms increased in value {1.0-200.0:multiple} times what you invested. :money_bag: That means you made ${=successes * multiple * individual_investment:cash_in}, and your exit multiple is {=cash_in/cash_out:exit_multiple}x. Good job! (As long as it was way above 1x, better if it's above 5x, otherwise bad job.) :+1: :+1: :+1: :flag-us: :flag-us: :flag-us: +XXX {=if(exit_multiple > 5, text("good"), text("bad")):job} + +{#failures by success} + From b4fcf5c217741d2c30cbd3f2e1f0b50c9acd27d2 Mon Sep 17 00:00:00 2001 From: Paul Ford Date: Sun, 10 May 2020 14:15:20 -0400 Subject: [PATCH 4/5] chore: run prettier --- src/App.js | 6 +- src/LineChart.js | 81 ++++++++++--------- src/Section.js | 184 +++++++++++++++++++++++--------------------- src/smarter-text.js | 151 ++++++++++++++++++------------------ 4 files changed, 215 insertions(+), 207 deletions(-) diff --git a/src/App.js b/src/App.js index 16cf7aa..6f50ecf 100644 --- a/src/App.js +++ b/src/App.js @@ -37,11 +37,11 @@ const textVars = textFiles.reduce( function App(props) { let { page } = useParams(); - const [ast, astState, ranges] = textVars[page]; + const [ast, astState, ranges] = textVars[page]; return (
-
-
); } diff --git a/src/LineChart.js b/src/LineChart.js index f28c443..34fde1c 100644 --- a/src/LineChart.js +++ b/src/LineChart.js @@ -1,47 +1,46 @@ import React from "react"; -import { ResponsiveLine } from '@nivo/line' +import { ResponsiveLine } from "@nivo/line"; function LineChart(props) { - return ( - - ) - + return ( + + ); } export default LineChart; diff --git a/src/Section.js b/src/Section.js index 0e446e2..124a0a0 100644 --- a/src/Section.js +++ b/src/Section.js @@ -5,17 +5,16 @@ import React, { useMemo } from "react"; import Slider from "./Slider"; import Statement from "./Statement"; import Text from "./Text"; -import LineChart from './LineChart'; - +import LineChart from "./LineChart"; import "./Section.css"; function Section(props) { - const { ast, astState, ranges } = props; - const searchParams = useSearchParams("replace"); - const state = useMemo(readFields, [astState, searchParams]); + const { ast, astState, ranges } = props; + const searchParams = useSearchParams("replace"); + const state = useMemo(readFields, [astState, searchParams]); - function addField(k, v) { + function addField(k, v) { searchParams.set(k, v); return v; } @@ -28,55 +27,60 @@ function Section(props) { ); } - function toComponents(o, i) { - switch (o.type) { - + function toComponents(o, i) { + switch (o.type) { case "chart": - const range = ranges[o.x].range; - const exp = ranges[o.y]; - let s = Object.assign(state); - - const inner_data = range.map( - (val,i)=>{ - s[o.x] = val; - Object.keys(ranges).forEach(x=>{ - if (ranges[x].type==='expression') { - s[x] = ranges[x].eval(s); - } - }) - const y = exp.eval(s); - return ({x:val, y:y}) - } - ); - const _minValue = inner_data[0].y; - const _maxValue = inner_data[inner_data.length - 1].y; + const range = ranges[o.x].range; + const exp = ranges[o.y]; + let s = Object.assign(state); + + const inner_data = range.map((val, i) => { + s[o.x] = val; + Object.keys(ranges).forEach((x) => { + if (ranges[x].type === "expression") { + s[x] = ranges[x].eval(s); + } + }); + const y = exp.eval(s); + return { x: val, y: y }; + }); + const _minValue = inner_data[0].y; + const _maxValue = inner_data[inner_data.length - 1].y; - const [minValue, maxValue] = [_minValue, _maxValue].sort((a,b)=>a-b); - const data = [{ - id:o.y, - data:inner_data - }]; - function c(x) { - return x.replace(/_/g, ' ').toUpperCase(); - - } - return
-

{c(o.y)} vs. {c(o.x)}

- numeral(x).format('-0,0')} - yFormat={(x)=>{ - console.log('Y',x); - return numeral(x).format('-0,0')}} - minValue={minValue} - maxValue={maxValue} - xLabel={c(o.x)} - yLabel={c(o.y)}/> -
+ const [minValue, maxValue] = [_minValue, _maxValue].sort( + (a, b) => a - b + ); + const data = [ + { + id: o.y, + data: inner_data, + }, + ]; + function c(x) { + return x.replace(/_/g, " ").toUpperCase(); + } + return ( +
+

+ {c(o.y)} vs. {c(o.x)} +

+ numeral(x).format("-0,0")} + yFormat={(x) => { + console.log("Y", x); + return numeral(x).format("-0,0"); + }} + minValue={minValue} + maxValue={maxValue} + xLabel={c(o.x)} + yLabel={c(o.y)} + /> +
+ ); case "paragraph": - return
- + return
; + case "text": return ; @@ -95,45 +99,49 @@ function Section(props) { ); case "expression": - function format(n) { - const num = numeral(n); - if (n < 10 && n > -10) { - return num.format("0.00"); - } - return num.format("-0,0"); - } - function evaluate(o) { - const n = o.eval(state); - state[o.variable] = n; - return n; + function format(n) { + const num = numeral(n); + if (n < 10 && n > -10) { + return num.format("0.00"); } - function newNum() { - const n = o.eval(); - state[o.variable] = n; - addField(o.variable, n); - console.log(o.variable, n, state[o.variable]); - } - - const n = evaluate(o); - const sign = n > 0 ? "positive" : "negative"; + return num.format("-0,0"); + } + function evaluate(o) { + const n = o.eval(state); + state[o.variable] = n; + return n; + } + function newNum() { + const n = o.eval(); + state[o.variable] = n; + addField(o.variable, n); + console.log(o.variable, n, state[o.variable]); + } + + const n = evaluate(o); + const sign = n > 0 ? "positive" : "negative"; + + if (o.interactive) { + return ( + + ); + } else { + return ( + + {format(n)} + + ); + } - if (o.interactive) { - - return - - } - else { - return ( - - {format(n)} - - ); - } - default: - return undefined; - } - } + return undefined; + } + } return (
diff --git a/src/smarter-text.js b/src/smarter-text.js index cd013cb..739f172 100644 --- a/src/smarter-text.js +++ b/src/smarter-text.js @@ -1,12 +1,9 @@ const P = require("parsimmon"); const ExpressionParser = require("expr-eval").Parser; - - - const Exp = new ExpressionParser(); Exp.functions.text = function (txt) { - return ""+txt; + return "" + txt; }; const numeral = require("numeral"); @@ -65,8 +62,8 @@ function explainDecimal(d) { function makeExpression(parseResult, kind) { const [expression, variable] = parseResult; return { - type:"expression", - interactive:kind==="interactive", + type: "expression", + interactive: kind === "interactive", format: kind, expression: expression, value: undefined, @@ -100,12 +97,15 @@ const docParser = P.createLanguage({ // that; it wants hierarchy. Without that, the parser fails and // says (most often) that it was expecting EOF. - Doc: (r) => P.alt(r.InteractiveExpression, - r.DecimalExpression, - r.ChartExpression, - r.Statement, - r.Paragraph, - r.Text).many(), + Doc: (r) => + P.alt( + r.InteractiveExpression, + r.DecimalExpression, + r.ChartExpression, + r.Statement, + r.Paragraph, + r.Text + ).many(), Statement: (r) => P.alt(r.DollarStatement, r.PercentageStatement, r.DecimalStatement), @@ -125,43 +125,50 @@ const docParser = P.createLanguage({ makeStatement(x, "percentage") ), - DollarExpression: (r) => P.seq(P.string("$"), r.DecimalExpression).map((x) => + DollarExpression: (r) => + P.seq(P.string("$"), r.DecimalExpression).map((x) => makeExpression(x, "dollar") ), - PercentageExpression: (r) => + PercentageExpression: (r) => P.seq(r.DecimalExpression, P.string("%")).map((x) => makeExpression(x, "percentage") ), - PlainExpression: (r) => P.string("{=").then(r.MathPair).skip(P.string("}")), - - - DecimalExpression: (r) => r.PlainExpression.map((x) => makeExpression(x, "decimal")), - - - ChartExpression: (r) => P.string("{#").then(r.ChartPair).skip(P.string("}")).map(x=>({type:"chart", y:x[0], x:x[1]})), - - InteractiveExpression: (r) => P.string("{!=").then(r.MathPair).skip(P.string("}")).map((x)=>makeExpression(x, "interactive")), - - Pair: (r) => P.seq(r.Range.skip(P.string(":")), r.Variable), - - MathPair: (r) => P.seq(r.Math.skip(P.string(":")), r.Variable), - - Range: (r) => P.sepBy1(r.Decimal, P.string("-")).map(makeRange), - - ChartPair: (r) => P.sepBy1(r.Variable, P.string(" by ")), - - Variable: (r) => P.regexp(/[a-z_]+/), - - Math: (r) => P.regexp(/[^:]+/), - - Decimal: (r) => P.regexp(/[+-]?[0-9.]+/).map(explainDecimal), - - Paragraph: (r) => P.newline.times(2).map(x=>({type: "paragraph"})), - - Text: (r) => - + PlainExpression: (r) => P.string("{=").then(r.MathPair).skip(P.string("}")), + + DecimalExpression: (r) => + r.PlainExpression.map((x) => makeExpression(x, "decimal")), + + ChartExpression: (r) => + P.string("{#") + .then(r.ChartPair) + .skip(P.string("}")) + .map((x) => ({ type: "chart", y: x[0], x: x[1] })), + + InteractiveExpression: (r) => + P.string("{!=") + .then(r.MathPair) + .skip(P.string("}")) + .map((x) => makeExpression(x, "interactive")), + + Pair: (r) => P.seq(r.Range.skip(P.string(":")), r.Variable), + + MathPair: (r) => P.seq(r.Math.skip(P.string(":")), r.Variable), + + Range: (r) => P.sepBy1(r.Decimal, P.string("-")).map(makeRange), + + ChartPair: (r) => P.sepBy1(r.Variable, P.string(" by ")), + + Variable: (r) => P.regexp(/[a-z_]+/), + + Math: (r) => P.regexp(/[^:]+/), + + Decimal: (r) => P.regexp(/[+-]?[0-9.]+/).map(explainDecimal), + + Paragraph: (r) => P.newline.times(2).map((x) => ({ type: "paragraph" })), + + Text: (r) => P.alt(P.any, P.whitespace).map((x) => ({ type: "text", value: x })), }); @@ -181,43 +188,37 @@ function parse(text) { return arr.concat(el); }, []); - let state = concatted.reduce(function (obj, value) { - if (value.type === "interactive") { - console.log('INTERACTIVE', value); - Object.assign(obj, { [value.variable]: value.value }); - } - else if (value.type === "statement") { - Object.assign(obj, { [value.variable]: value.value.value }); - } - else if (value.type === "expression") { - Object.assign(obj, { [value.variable]: value.value }); - } + if (value.type === "interactive") { + console.log("INTERACTIVE", value); + Object.assign(obj, { [value.variable]: value.value }); + } else if (value.type === "statement") { + Object.assign(obj, { [value.variable]: value.value.value }); + } else if (value.type === "expression") { + Object.assign(obj, { [value.variable]: value.value }); + } return obj; }, {}); + let ranges = concatted.reduce(function (obj, value) { + let vv = value.value; - let ranges = concatted.reduce(function (obj, value) { - let vv = value.value; - - if (value.type === "statement") { - const ARRAY_SIZE = 10; - let arr = []; - const tick = (vv.max - vv.min)/ARRAY_SIZE; - for (let i = vv.min; i <= vv.max; i = i + tick) { - const j = Math.round(i) - arr.push(j); - } - arr.sort((a,b)=>a-b); - vv['range'] = arr - Object.assign(obj, { [value.variable]: vv }); - } - else if (value.type === "expression") { - Object.assign(obj, { [value.variable]: value }); - } - return obj; - }, {}); - + if (value.type === "statement") { + const ARRAY_SIZE = 10; + let arr = []; + const tick = (vv.max - vv.min) / ARRAY_SIZE; + for (let i = vv.min; i <= vv.max; i = i + tick) { + const j = Math.round(i); + arr.push(j); + } + arr.sort((a, b) => a - b); + vv["range"] = arr; + Object.assign(obj, { [value.variable]: vv }); + } else if (value.type === "expression") { + Object.assign(obj, { [value.variable]: value }); + } + return obj; + }, {}); const mathed = concatted.filter((o) => o.type === "expression"); mathed.map((el) => { @@ -225,7 +226,7 @@ function parse(text) { return true; }); - return [concatted, state, ranges]; + return [concatted, state, ranges]; } // var fs = require("fs"); From 88d6ac5e890d4ee89b0ff6675de8efe41bf4d649 Mon Sep 17 00:00:00 2001 From: Paul Ford Date: Fri, 15 May 2020 17:16:50 -0400 Subject: [PATCH 5/5] bug: fix hamburger --- src/LineChart.js | 12 ++++++++---- src/Nav.css | 6 +++--- src/Nav.js | 8 ++++---- src/Section.css | 3 ++- src/texts/agency.txt | 14 ++++++++++++++ src/texts/apples.txt | 0 src/texts/freelancer.txt | 16 ++-------------- src/texts/hankies.txt | 4 +++- src/texts/pfwiki.txt | 14 ++++++++++++++ src/texts/soda.txt | 2 +- 10 files changed, 51 insertions(+), 28 deletions(-) create mode 100644 src/texts/agency.txt create mode 100644 src/texts/apples.txt create mode 100644 src/texts/pfwiki.txt diff --git a/src/LineChart.js b/src/LineChart.js index 34fde1c..f341f5d 100644 --- a/src/LineChart.js +++ b/src/LineChart.js @@ -6,14 +6,18 @@ function LineChart(props) { setHamburgerOpen(hamburgerOpen ? false : true)} - width={80} - height={50} - strokeWidth={3} - rotate={45} + width={30} + height={20} + strokeWidth={4} + rotate={0} animationDuration={0.2} className="burger" color="slategray" diff --git a/src/Section.css b/src/Section.css index 899ecd9..13072cc 100644 --- a/src/Section.css +++ b/src/Section.css @@ -22,11 +22,12 @@ div.spacer { .chart { height:325px; border:1px solid #ccc; - padding:0px 50px 120px 1em; + padding:0px 20px 120px 0.5em; background:#fafafa; } .chart h3 { + font-size:1.25em; font-weight:200; } diff --git a/src/texts/agency.txt b/src/texts/agency.txt new file mode 100644 index 0000000..2bc380f --- /dev/null +++ b/src/texts/agency.txt @@ -0,0 +1,14 @@ + +A week is {20-60:hours} hours and there are {26-52:weeks} working weeks in a year. + +You have a staff of {200:number_of_staff} and on average you pay them ${150:staff_rate}/hr. So you have {=number_of_staff * weeks * hours:staff_hours} hours available per year, for which you pay ${=staff_rate*staff_hours:staff_expense}. + +You can generate work from {20:number_of_clients} clients over a year. Your average client needs a team of {20:team_size} and pays ${150:client_rate} per hour per person. A typical project runs about {0-52:project_weeks} weeks. So they are asking for {=number_of_clients * team_size * project_weeks * hours:client_hours} hours of work per year ({=client_hours/hours/weeks:person_years} person-years), for ${=client_rate*client_hours:client_revenue}. +(At current staffing you can fulfill {=number_of_staff/person_years * 100:staffing_ratio}% of that.) This means that your profit is +${= +available_staff = if(person_years < number_of_staff, person_years, number_of_staff); +actual_client_revenue = available_staff * hours * weeks * client_rate; +actual_client_revenue - staff_expense +:profit}. + +{#profit by number_of_clients} diff --git a/src/texts/apples.txt b/src/texts/apples.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/texts/freelancer.txt b/src/texts/freelancer.txt index 3cd7713..8c87385 100644 --- a/src/texts/freelancer.txt +++ b/src/texts/freelancer.txt @@ -1,15 +1,3 @@ -:green_book: You are a freelance writer. +:green_book: You are a freelance writer. You're able to charge ${0.01-3.00:rate} per word. :money_bag: You get {1-6:monthly_assignments} assignments a month, at an average length of {300-3000:words} words. This means that you make ${=rate * monthly_assignments * words:monthly} a month (assuming they pay), or ${=12*monthly:annual} a year, assuming this holds steady and everyone pays. :money_with_wings: Taxes at {20:average_tax}% will leave you with ${=annual * (1 - average_tax/100):after_taxes}. If you pay ${2000:rent} a month in rent and ${683:insurance} a month for insurance this leaves you with ${=after_taxes - (rent * 12) - (insurance * 12):annual_profit} for :children_crossing: everything :takeout_box: else :airplane: you :pill: need, or just for you.:+1: -You're able to charge ${0.01-3.00:rate} per word. - -:money_bag: You get {1-6:assignments} assignments a month, at an average length of {300-3000:words} words. - -This means that you make ${=rate * assignments * words:monthly} a month (assuming they pay), or ${=12*monthly:annual} a year, assuming this holds steady and everyone pays. - -:money_with_wings: Taxes at {20:average_tax}% will leave you with ${=annual * (1 - average_tax/100):after_taxes}. - -If you pay ${2000:rent} a month in rent and ${683:insurance} a month for insurance this leaves you with - -${=after_taxes - (rent * 12) - (insurance * 12):profit} - -for :children_crossing: everything :takeout_box: else :airplane: you :pill: need, or just for you.:+1: +{#annual_profit by monthly_assignments} diff --git a/src/texts/hankies.txt b/src/texts/hankies.txt index 65d2104..8100d98 100644 --- a/src/texts/hankies.txt +++ b/src/texts/hankies.txt @@ -2,4 +2,6 @@ If you buy boxes of {65:perbox} tissues and blow your :nose: {5:blows} times a day, in {5:years} years you'd use {=(blows*(365*years))/perbox:boxes} boxes. At ${1.50:costperbox} per box, that would cost you ${=costperbox * boxes:tissuespend}. :money_with_wings: -If you switched to a set of ${5-15:hankiespend} hankerchiefs :sneezing_face: you'd save ${= tissuespend - hankiespend :savings} and several trees. :deciduous_tree: :sunflower: :deciduous_tree: :tulip: :deciduous_tree: :rose: :deciduous_tree: \ No newline at end of file +If you switched to a set of ${5-15:hankiespend} hankerchiefs :sneezing_face: you'd save ${= tissuespend - hankiespend :savings} and several trees. :deciduous_tree: :sunflower: :deciduous_tree: :tulip: :deciduous_tree: :rose: :deciduous_tree: + +{#savings by blows} diff --git a/src/texts/pfwiki.txt b/src/texts/pfwiki.txt new file mode 100644 index 0000000..38b0e20 --- /dev/null +++ b/src/texts/pfwiki.txt @@ -0,0 +1,14 @@ +Probable Futures has a wiki. It has {10:theme_count} themes and each theme takes {80:theme_hours} hours to fully craft, research, and write. + +Each theme has {5:major_count} major entries and each minor theme takes {40:major_hours} hours to research and write. + +Each major theme links to {20:entry_count} entries, and each entry takes {6:entry_hours} hours to craft. + +This means we've got {=theme_count + (theme_count * major_count) + (theme_count * major_count * entry_count):nodes} individual content items. +Thus we have a total of {= +theme_count * theme_hours ++ (theme_count * major_count * major_hours) ++ (theme_count * major_count * entry_count * entry_hours) +:total_hours} total hours, or {=total_hours/40/4:months} months ({=months/12:total_years} years) of human effort. + +{#total_hours by theme_count} diff --git a/src/texts/soda.txt b/src/texts/soda.txt index 7f69d63..a4ff65c 100644 --- a/src/texts/soda.txt +++ b/src/texts/soda.txt @@ -12,4 +12,4 @@ monthly_costs * ((((1 + adjusted)^period) - 1) / adjusted) :total_saved} in a decade. -{#total_saved by daily_sodas} +