Add multiple exported graphs (broken)
This commit is contained in:
parent
01990dbe9f
commit
afd1481177
|
@ -37,7 +37,7 @@
|
||||||
"@glennsl/bs-json",
|
"@glennsl/bs-json",
|
||||||
"@foretold/components",
|
"@foretold/components",
|
||||||
"bs-ant-design-alt",
|
"bs-ant-design-alt",
|
||||||
"reason-react",
|
"@rescript/react",
|
||||||
"bs-reform",
|
"bs-reform",
|
||||||
"bs-css",
|
"bs-css",
|
||||||
"rationale",
|
"rationale",
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@foretold/components": "./foretold/components",
|
"@foretold/components": "./foretold/components",
|
||||||
"@glennsl/bs-json": "^5.0.2",
|
"@glennsl/bs-json": "^5.0.2",
|
||||||
|
"@rescript/react": "^0.10.3",
|
||||||
"ace-builds": "^1.4.12",
|
"ace-builds": "^1.4.12",
|
||||||
"antd": "3.17.0",
|
"antd": "3.17.0",
|
||||||
"autoprefixer": "9.7.4",
|
"autoprefixer": "9.7.4",
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
|
|
||||||
var reasonReactBlue = "#48a9dc";
|
|
||||||
|
|
||||||
var style = "\n body {\n background-color: rgb(224, 226, 229);\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n button {\n background-color: white;\n color: " + reasonReactBlue + ";\n box-shadow: 0 0 0 1px " + reasonReactBlue + ";\n border: none;\n padding: 8px;\n font-size: 16px;\n }\n button:active {\n background-color: " + reasonReactBlue + ";\n color: white;\n }\n .container {\n margin: 12px 0px;\n box-shadow: 0px 4px 16px rgb(200, 200, 200);\n width: 720px;\n border-radius: 12px;\n font-family: sans-serif;\n }\n .containerTitle {\n background-color: rgb(242, 243, 245);\n border-radius: 12px 12px 0px 0px;\n padding: 12px;\n font-weight: bold;\n }\n .containerContent {\n background-color: white;\n padding: 16px;\n border-radius: 0px 0px 12px 12px;\n }\n";
|
|
||||||
|
|
||||||
exports.reasonReactBlue = reasonReactBlue;
|
|
||||||
exports.style = style;
|
|
||||||
/* No side effect */
|
|
|
@ -1,345 +0,0 @@
|
||||||
open ReForm;
|
|
||||||
open Antd.Grid;
|
|
||||||
|
|
||||||
module FormConfig = [%lenses
|
|
||||||
type state = {
|
|
||||||
squiggleString: string,
|
|
||||||
sampleCount: string,
|
|
||||||
outputXYPoints: string,
|
|
||||||
downsampleTo: string,
|
|
||||||
kernelWidth: string,
|
|
||||||
diagramStart: string,
|
|
||||||
diagramStop: string,
|
|
||||||
diagramCount: string,
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
type options = {
|
|
||||||
sampleCount: int,
|
|
||||||
outputXYPoints: int,
|
|
||||||
downsampleTo: option(int),
|
|
||||||
kernelWidth: option(float),
|
|
||||||
diagramStart: float,
|
|
||||||
diagramStop: float,
|
|
||||||
diagramCount: int,
|
|
||||||
};
|
|
||||||
|
|
||||||
module Form = ReForm.Make(FormConfig);
|
|
||||||
|
|
||||||
module FieldText = {
|
|
||||||
[@react.component]
|
|
||||||
let make = (~field, ~label) => {
|
|
||||||
<>
|
|
||||||
<Form.Field
|
|
||||||
field
|
|
||||||
render={({handleChange, error, value, validate}) =>
|
|
||||||
<CodeEditor value onChange={r => handleChange(r)} />
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
module FieldString = {
|
|
||||||
[@react.component]
|
|
||||||
let make = (~field, ~label) => {
|
|
||||||
<Form.Field
|
|
||||||
field
|
|
||||||
render={({handleChange, error, value, validate}) =>
|
|
||||||
<Antd.Form.Item label={label |> R.ste}>
|
|
||||||
<Antd.Input
|
|
||||||
value
|
|
||||||
onChange={ReForm.Helpers.handleChange(handleChange)}
|
|
||||||
onBlur={_ => validate()}
|
|
||||||
/>
|
|
||||||
</Antd.Form.Item>
|
|
||||||
}
|
|
||||||
/>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module FieldFloat = {
|
|
||||||
[@react.component]
|
|
||||||
let make = (~field, ~label, ~className=Css.style([])) => {
|
|
||||||
<Form.Field
|
|
||||||
field
|
|
||||||
render={({handleChange, error, value, validate}) =>
|
|
||||||
<Antd.Form.Item label={label |> R.ste}>
|
|
||||||
<Antd.Input
|
|
||||||
value
|
|
||||||
onChange={ReForm.Helpers.handleChange(handleChange)}
|
|
||||||
onBlur={_ => validate()}
|
|
||||||
className
|
|
||||||
/>
|
|
||||||
</Antd.Form.Item>
|
|
||||||
}
|
|
||||||
/>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module Styles = {
|
|
||||||
open Css;
|
|
||||||
let rows =
|
|
||||||
style([
|
|
||||||
selector(
|
|
||||||
">.ant-col:first-child",
|
|
||||||
[paddingLeft(em(0.25)), paddingRight(em(0.125))],
|
|
||||||
),
|
|
||||||
selector(
|
|
||||||
">.ant-col:last-child",
|
|
||||||
[paddingLeft(em(0.125)), paddingRight(em(0.25))],
|
|
||||||
),
|
|
||||||
selector(
|
|
||||||
">.ant-col:not(:first-child):not(:last-child)",
|
|
||||||
[paddingLeft(em(0.125)), paddingRight(em(0.125))],
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
let parent =
|
|
||||||
style([
|
|
||||||
selector(".ant-input-number", [width(`percent(100.))]),
|
|
||||||
selector(".anticon", [verticalAlign(`zero)]),
|
|
||||||
]);
|
|
||||||
let form = style([backgroundColor(hex("eee")), padding(em(1.))]);
|
|
||||||
let dist = style([padding(em(1.))]);
|
|
||||||
let spacer = style([marginTop(em(1.))]);
|
|
||||||
let groupA =
|
|
||||||
style([
|
|
||||||
selector(
|
|
||||||
".ant-input-number-input",
|
|
||||||
[backgroundColor(hex("fff7db"))],
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
let groupB =
|
|
||||||
style([
|
|
||||||
selector(
|
|
||||||
".ant-input-number-input",
|
|
||||||
[backgroundColor(hex("eaf4ff"))],
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
module DemoDist = {
|
|
||||||
[@react.component]
|
|
||||||
let make = (~squiggleString:string, ~options) => {
|
|
||||||
<Antd.Card title={"Distribution" |> R.ste}>
|
|
||||||
<div>
|
|
||||||
{switch (options) {
|
|
||||||
| Some(options) =>
|
|
||||||
let inputs1 =
|
|
||||||
ProgramEvaluator.Inputs.make(
|
|
||||||
~samplingInputs={
|
|
||||||
sampleCount: Some(options.sampleCount),
|
|
||||||
outputXYPoints: Some(options.outputXYPoints),
|
|
||||||
kernelWidth: options.kernelWidth,
|
|
||||||
shapeLength:
|
|
||||||
Some(options.downsampleTo |> E.O.default(1000)),
|
|
||||||
},
|
|
||||||
~squiggleString,
|
|
||||||
~environment=
|
|
||||||
[|
|
|
||||||
("K", `SymbolicDist(`Float(1000.0))),
|
|
||||||
("M", `SymbolicDist(`Float(1000000.0))),
|
|
||||||
("B", `SymbolicDist(`Float(1000000000.0))),
|
|
||||||
("T", `SymbolicDist(`Float(1000000000000.0))),
|
|
||||||
|]
|
|
||||||
->Belt.Map.String.fromArray,
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let response1 = ProgramEvaluator.evaluateProgram(inputs1);
|
|
||||||
switch (response1) {
|
|
||||||
| Ok(`DistPlus(distPlus1)) =>
|
|
||||||
<DistPlusPlot distPlus={DistPlus.T.normalize(distPlus1)} />
|
|
||||||
| Ok(`Float(f)) =>
|
|
||||||
<ForetoldComponents.NumberShower number=f precision=3 />
|
|
||||||
| Ok(`Function((f, a), env)) =>
|
|
||||||
// Problem: When it gets the function, it doesn't save state about previous commands
|
|
||||||
let foo: ProgramEvaluator.Inputs.inputs = {
|
|
||||||
squiggleString,
|
|
||||||
samplingInputs: inputs1.samplingInputs,
|
|
||||||
environment: env,
|
|
||||||
};
|
|
||||||
let results =
|
|
||||||
E.A.Floats.range(options.diagramStart, options.diagramStop, options.diagramCount)
|
|
||||||
|> E.A.fmap(r =>
|
|
||||||
ProgramEvaluator.evaluateFunction(
|
|
||||||
foo,
|
|
||||||
(f, a),
|
|
||||||
[|`SymbolicDist(`Float(r))|],
|
|
||||||
)
|
|
||||||
|> E.R.bind(_, a =>
|
|
||||||
switch (a) {
|
|
||||||
| `DistPlus(d) => Ok((r, DistPlus.T.normalize(d)))
|
|
||||||
| n =>
|
|
||||||
Js.log2("Error here", n);
|
|
||||||
Error("wrong type");
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|> E.A.R.firstErrorOrOpen;
|
|
||||||
switch (results) {
|
|
||||||
| Ok(dists) => <PercentilesChart dists />
|
|
||||||
| Error(r) => r |> R.ste
|
|
||||||
};
|
|
||||||
| Error(r) => r |> R.ste
|
|
||||||
};
|
|
||||||
| _ =>
|
|
||||||
"Nothing to show. Try to change the distribution description."
|
|
||||||
|> R.ste
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</Antd.Card>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
[@react.component]
|
|
||||||
let make = () => {
|
|
||||||
let (reloader, setReloader) = React.useState(() => 1);
|
|
||||||
let reform =
|
|
||||||
Form.use(
|
|
||||||
~validationStrategy=OnDemand,
|
|
||||||
~schema=Form.Validation.Schema([||]),
|
|
||||||
~onSubmit=({state}) => {None},
|
|
||||||
~initialState={
|
|
||||||
//squiggleString: "mm(normal(-10, 2), uniform(18, 25), lognormal({mean: 10, stdev: 8}), triangular(31,40,50))",
|
|
||||||
squiggleString: "mm(normal(5,2), normal(10,2))",
|
|
||||||
sampleCount: "1000",
|
|
||||||
outputXYPoints: "1000",
|
|
||||||
downsampleTo: "",
|
|
||||||
kernelWidth: "",
|
|
||||||
diagramStart: "0",
|
|
||||||
diagramStop: "10",
|
|
||||||
diagramCount: "20",
|
|
||||||
},
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let onSubmit = e => {
|
|
||||||
e->ReactEvent.Synthetic.preventDefault;
|
|
||||||
reform.submit();
|
|
||||||
};
|
|
||||||
|
|
||||||
let squiggleString = reform.state.values.squiggleString;
|
|
||||||
let sampleCount = reform.state.values.sampleCount |> Js.Float.fromString;
|
|
||||||
let outputXYPoints =
|
|
||||||
reform.state.values.outputXYPoints |> Js.Float.fromString;
|
|
||||||
let downsampleTo = reform.state.values.downsampleTo |> Js.Float.fromString;
|
|
||||||
let kernelWidth = reform.state.values.kernelWidth |> Js.Float.fromString;
|
|
||||||
let diagramStart = reform.state.values.diagramStart |> Js.Float.fromString;
|
|
||||||
let diagramStop = reform.state.values.diagramStop |> Js.Float.fromString;
|
|
||||||
let diagramCount = reform.state.values.diagramCount |> Js.Float.fromString;
|
|
||||||
|
|
||||||
let options =
|
|
||||||
switch (sampleCount, outputXYPoints, downsampleTo) {
|
|
||||||
| (_, _, _)
|
|
||||||
when
|
|
||||||
!Js.Float.isNaN(sampleCount)
|
|
||||||
&& !Js.Float.isNaN(outputXYPoints)
|
|
||||||
&& !Js.Float.isNaN(downsampleTo)
|
|
||||||
&& sampleCount > 10.
|
|
||||||
&& outputXYPoints > 10. =>
|
|
||||||
Some({
|
|
||||||
sampleCount: sampleCount |> int_of_float,
|
|
||||||
outputXYPoints: outputXYPoints |> int_of_float,
|
|
||||||
downsampleTo:
|
|
||||||
int_of_float(downsampleTo) > 0
|
|
||||||
? Some(int_of_float(downsampleTo)) : None,
|
|
||||||
kernelWidth: kernelWidth == 0.0 ? None : Some(kernelWidth),
|
|
||||||
diagramStart: diagramStart,
|
|
||||||
diagramStop: diagramStop,
|
|
||||||
diagramCount: diagramCount |> int_of_float,
|
|
||||||
})
|
|
||||||
| _ => None
|
|
||||||
};
|
|
||||||
|
|
||||||
let demoDist =
|
|
||||||
React.useMemo1(
|
|
||||||
() => <DemoDist squiggleString options />,
|
|
||||||
[|
|
|
||||||
reform.state.values.squiggleString,
|
|
||||||
reform.state.values.sampleCount,
|
|
||||||
reform.state.values.outputXYPoints,
|
|
||||||
reform.state.values.downsampleTo,
|
|
||||||
reform.state.values.kernelWidth,
|
|
||||||
reform.state.values.diagramStart,
|
|
||||||
reform.state.values.diagramStop,
|
|
||||||
reform.state.values.diagramCount,
|
|
||||||
reloader |> string_of_int,
|
|
||||||
|],
|
|
||||||
);
|
|
||||||
|
|
||||||
let onReload = _ => {
|
|
||||||
setReloader(_ => reloader + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<Antd.Card
|
|
||||||
title={"Distribution Form" |> R.ste}
|
|
||||||
extra={
|
|
||||||
<Antd.Button
|
|
||||||
icon=Antd.IconName.reload
|
|
||||||
shape=`circle
|
|
||||||
onClick=onReload
|
|
||||||
/>
|
|
||||||
}>
|
|
||||||
<Form.Provider value=reform>
|
|
||||||
<Antd.Form onSubmit>
|
|
||||||
<Row _type=`flex className=Styles.rows>
|
|
||||||
<Col span=24>
|
|
||||||
<FieldText
|
|
||||||
field=FormConfig.SquiggleString
|
|
||||||
label="Program"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row _type=`flex className=Styles.rows>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat
|
|
||||||
field=FormConfig.SampleCount
|
|
||||||
label="Sample Count"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat
|
|
||||||
field=FormConfig.OutputXYPoints
|
|
||||||
label="Output XY-points"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat
|
|
||||||
field=FormConfig.DownsampleTo
|
|
||||||
label="Downsample To"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat
|
|
||||||
field=FormConfig.KernelWidth
|
|
||||||
label="Kernel Width"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat
|
|
||||||
field=FormConfig.DiagramStart
|
|
||||||
label="Diagram Start"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat
|
|
||||||
field=FormConfig.DiagramStop
|
|
||||||
label="Diagram Stop"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat
|
|
||||||
field=FormConfig.DiagramCount
|
|
||||||
label="Diagram Count"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Antd.Form>
|
|
||||||
</Form.Provider>
|
|
||||||
</Antd.Card>
|
|
||||||
</div>
|
|
||||||
<div> demoDist </div>
|
|
||||||
</div>;
|
|
||||||
};
|
|
271
src/components/DistBuilder.res
Normal file
271
src/components/DistBuilder.res
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
open ReForm
|
||||||
|
open Antd.Grid
|
||||||
|
|
||||||
|
module FormConfig = %lenses(
|
||||||
|
type state = {
|
||||||
|
squiggleString: string,
|
||||||
|
sampleCount: string,
|
||||||
|
outputXYPoints: string,
|
||||||
|
downsampleTo: string,
|
||||||
|
kernelWidth: string,
|
||||||
|
diagramStart: string,
|
||||||
|
diagramStop: string,
|
||||||
|
diagramCount: string,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type options = {
|
||||||
|
sampleCount: int,
|
||||||
|
outputXYPoints: int,
|
||||||
|
downsampleTo: option<int>,
|
||||||
|
kernelWidth: option<float>,
|
||||||
|
diagramStart: float,
|
||||||
|
diagramStop: float,
|
||||||
|
diagramCount: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
module Form = ReForm.Make(FormConfig)
|
||||||
|
|
||||||
|
module FieldText = {
|
||||||
|
@react.component
|
||||||
|
let make = (~field, ~label) => <>
|
||||||
|
<Form.Field
|
||||||
|
field
|
||||||
|
render={({handleChange, error, value, validate}) =>
|
||||||
|
<CodeEditor value onChange={r => handleChange(r)} />}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
module FieldString = {
|
||||||
|
@react.component
|
||||||
|
let make = (~field, ~label) =>
|
||||||
|
<Form.Field
|
||||||
|
field
|
||||||
|
render={({handleChange, error, value, validate}) =>
|
||||||
|
<Antd.Form.Item label={label |> R.ste}>
|
||||||
|
<Antd.Input
|
||||||
|
value onChange={ReForm.Helpers.handleChange(handleChange)} onBlur={_ => validate()}
|
||||||
|
/>
|
||||||
|
</Antd.Form.Item>}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
module FieldFloat = {
|
||||||
|
@react.component
|
||||||
|
let make = (~field, ~label, ~className=Css.style(list{})) =>
|
||||||
|
<Form.Field
|
||||||
|
field
|
||||||
|
render={({handleChange, error, value, validate}) =>
|
||||||
|
<Antd.Form.Item label={label |> R.ste}>
|
||||||
|
<Antd.Input
|
||||||
|
value
|
||||||
|
onChange={ReForm.Helpers.handleChange(handleChange)}
|
||||||
|
onBlur={_ => validate()}
|
||||||
|
className
|
||||||
|
/>
|
||||||
|
</Antd.Form.Item>}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
module Styles = {
|
||||||
|
open Css
|
||||||
|
let rows = style(list{
|
||||||
|
selector(">.ant-col:first-child", list{paddingLeft(em(0.25)), paddingRight(em(0.125))}),
|
||||||
|
selector(">.ant-col:last-child", list{paddingLeft(em(0.125)), paddingRight(em(0.25))}),
|
||||||
|
selector(
|
||||||
|
">.ant-col:not(:first-child):not(:last-child)",
|
||||||
|
list{paddingLeft(em(0.125)), paddingRight(em(0.125))},
|
||||||
|
),
|
||||||
|
})
|
||||||
|
let parent = style(list{
|
||||||
|
selector(".ant-input-number", list{width(#percent(100.))}),
|
||||||
|
selector(".anticon", list{verticalAlign(#zero)}),
|
||||||
|
})
|
||||||
|
let form = style(list{backgroundColor(hex("eee")), padding(em(1.))})
|
||||||
|
let dist = style(list{padding(em(1.))})
|
||||||
|
let spacer = style(list{marginTop(em(1.))})
|
||||||
|
let groupA = style(list{
|
||||||
|
selector(".ant-input-number-input", list{backgroundColor(hex("fff7db"))}),
|
||||||
|
})
|
||||||
|
let groupB = style(list{
|
||||||
|
selector(".ant-input-number-input", list{backgroundColor(hex("eaf4ff"))}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module DemoDist = {
|
||||||
|
@react.component
|
||||||
|
let make = (~squiggleString: string, ~options) =>
|
||||||
|
<Antd.Card title={"Distribution" |> R.ste}>
|
||||||
|
<div>
|
||||||
|
{switch options {
|
||||||
|
| Some(options) =>
|
||||||
|
let inputs1 = ProgramEvaluator.Inputs.make(
|
||||||
|
~samplingInputs={
|
||||||
|
sampleCount: Some(options.sampleCount),
|
||||||
|
outputXYPoints: Some(options.outputXYPoints),
|
||||||
|
kernelWidth: options.kernelWidth,
|
||||||
|
shapeLength: Some(options.downsampleTo |> E.O.default(1000)),
|
||||||
|
},
|
||||||
|
~squiggleString,
|
||||||
|
~environment=[
|
||||||
|
("K", #SymbolicDist(#Float(1000.0))),
|
||||||
|
("M", #SymbolicDist(#Float(1000000.0))),
|
||||||
|
("B", #SymbolicDist(#Float(1000000000.0))),
|
||||||
|
("T", #SymbolicDist(#Float(1000000000000.0))),
|
||||||
|
]->Belt.Map.String.fromArray,
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
|
||||||
|
let distributionList = ProgramEvaluator.evaluateProgram(inputs1)
|
||||||
|
|
||||||
|
let renderExpression = response1 =>
|
||||||
|
switch response1 {
|
||||||
|
| #DistPlus(distPlus1) => <DistPlusPlot distPlus={DistPlus.T.normalize(distPlus1)} />
|
||||||
|
| #Float(f) => <ForetoldComponents.NumberShower number=f precision=3 />
|
||||||
|
| #Function((f, a), env) =>
|
||||||
|
// Problem: When it gets the function, it doesn't save state about previous commands
|
||||||
|
let foo: ProgramEvaluator.Inputs.inputs = {
|
||||||
|
squiggleString: squiggleString,
|
||||||
|
samplingInputs: inputs1.samplingInputs,
|
||||||
|
environment: env,
|
||||||
|
}
|
||||||
|
let results =
|
||||||
|
E.A.Floats.range(options.diagramStart, options.diagramStop, options.diagramCount)
|
||||||
|
|> E.A.fmap(r =>
|
||||||
|
ProgramEvaluator.evaluateFunction(
|
||||||
|
foo,
|
||||||
|
(f, a),
|
||||||
|
[#SymbolicDist(#Float(r))],
|
||||||
|
) |> E.R.bind(_, a =>
|
||||||
|
switch a {
|
||||||
|
| #DistPlus(d) => Ok((r, DistPlus.T.normalize(d)))
|
||||||
|
| n =>
|
||||||
|
Js.log2("Error here", n)
|
||||||
|
Error("wrong type")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> E.A.R.firstErrorOrOpen
|
||||||
|
switch results {
|
||||||
|
| Ok(dists) => <PercentilesChart dists />
|
||||||
|
| Error(r) => r |> R.ste
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the list of distributions given by the
|
||||||
|
switch distributionList {
|
||||||
|
| Ok(xs) =>
|
||||||
|
let childrenElements = List.map(renderExpression, xs)
|
||||||
|
Js.Console.log(childrenElements)
|
||||||
|
@JSX div(~children=childrenElements, ())
|
||||||
|
| Error(r) => r |> R.ste
|
||||||
|
}
|
||||||
|
| _ => "Nothing to show. Try to change the distribution description." |> R.ste
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</Antd.Card>
|
||||||
|
}
|
||||||
|
|
||||||
|
@react.component
|
||||||
|
let make = () => {
|
||||||
|
let (reloader, setReloader) = React.useState(() => 1)
|
||||||
|
let reform = Form.use(
|
||||||
|
~validationStrategy=OnDemand,
|
||||||
|
~schema=Form.Validation.Schema([]),
|
||||||
|
~onSubmit=({state}) => None,
|
||||||
|
~initialState={
|
||||||
|
//squiggleString: "mm(normal(-10, 2), uniform(18, 25), lognormal({mean: 10, stdev: 8}), triangular(31,40,50))",
|
||||||
|
squiggleString: "mm(normal(5,2), normal(10,2))",
|
||||||
|
sampleCount: "1000",
|
||||||
|
outputXYPoints: "1000",
|
||||||
|
downsampleTo: "",
|
||||||
|
kernelWidth: "",
|
||||||
|
diagramStart: "0",
|
||||||
|
diagramStop: "10",
|
||||||
|
diagramCount: "20",
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
|
||||||
|
let onSubmit = e => {
|
||||||
|
e->ReactEvent.Synthetic.preventDefault
|
||||||
|
reform.submit()
|
||||||
|
}
|
||||||
|
|
||||||
|
let squiggleString = reform.state.values.squiggleString
|
||||||
|
let sampleCount = reform.state.values.sampleCount |> Js.Float.fromString
|
||||||
|
let outputXYPoints = reform.state.values.outputXYPoints |> Js.Float.fromString
|
||||||
|
let downsampleTo = reform.state.values.downsampleTo |> Js.Float.fromString
|
||||||
|
let kernelWidth = reform.state.values.kernelWidth |> Js.Float.fromString
|
||||||
|
let diagramStart = reform.state.values.diagramStart |> Js.Float.fromString
|
||||||
|
let diagramStop = reform.state.values.diagramStop |> Js.Float.fromString
|
||||||
|
let diagramCount = reform.state.values.diagramCount |> Js.Float.fromString
|
||||||
|
|
||||||
|
let options = switch (sampleCount, outputXYPoints, downsampleTo) {
|
||||||
|
| (_, _, _)
|
||||||
|
if !Js.Float.isNaN(sampleCount) &&
|
||||||
|
(!Js.Float.isNaN(outputXYPoints) &&
|
||||||
|
(!Js.Float.isNaN(downsampleTo) && (sampleCount > 10. && outputXYPoints > 10.))) =>
|
||||||
|
Some({
|
||||||
|
sampleCount: sampleCount |> int_of_float,
|
||||||
|
outputXYPoints: outputXYPoints |> int_of_float,
|
||||||
|
downsampleTo: int_of_float(downsampleTo) > 0 ? Some(int_of_float(downsampleTo)) : None,
|
||||||
|
kernelWidth: kernelWidth == 0.0 ? None : Some(kernelWidth),
|
||||||
|
diagramStart: diagramStart,
|
||||||
|
diagramStop: diagramStop,
|
||||||
|
diagramCount: diagramCount |> int_of_float,
|
||||||
|
})
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
|
||||||
|
let demoDist = React.useMemo1(
|
||||||
|
() => <DemoDist squiggleString options />,
|
||||||
|
[
|
||||||
|
reform.state.values.squiggleString,
|
||||||
|
reform.state.values.sampleCount,
|
||||||
|
reform.state.values.outputXYPoints,
|
||||||
|
reform.state.values.downsampleTo,
|
||||||
|
reform.state.values.kernelWidth,
|
||||||
|
reform.state.values.diagramStart,
|
||||||
|
reform.state.values.diagramStop,
|
||||||
|
reform.state.values.diagramCount,
|
||||||
|
reloader |> string_of_int,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
let onReload = _ => setReloader(_ => reloader + 1)
|
||||||
|
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<Antd.Card
|
||||||
|
title={"Distribution Form" |> R.ste}
|
||||||
|
extra={<Antd.Button icon=Antd.IconName.reload shape=#circle onClick=onReload />}>
|
||||||
|
<Form.Provider value=reform>
|
||||||
|
<Antd.Form onSubmit>
|
||||||
|
<Row _type=#flex className=Styles.rows>
|
||||||
|
<Col span=24> <FieldText field=FormConfig.SquiggleString label="Program" /> </Col>
|
||||||
|
</Row>
|
||||||
|
<Row _type=#flex className=Styles.rows>
|
||||||
|
<Col span=12> <FieldFloat field=FormConfig.SampleCount label="Sample Count" /> </Col>
|
||||||
|
<Col span=12>
|
||||||
|
<FieldFloat field=FormConfig.OutputXYPoints label="Output XY-points" />
|
||||||
|
</Col>
|
||||||
|
<Col span=12>
|
||||||
|
<FieldFloat field=FormConfig.DownsampleTo label="Downsample To" />
|
||||||
|
</Col>
|
||||||
|
<Col span=12> <FieldFloat field=FormConfig.KernelWidth label="Kernel Width" /> </Col>
|
||||||
|
<Col span=12>
|
||||||
|
<FieldFloat field=FormConfig.DiagramStart label="Diagram Start" />
|
||||||
|
</Col>
|
||||||
|
<Col span=12> <FieldFloat field=FormConfig.DiagramStop label="Diagram Stop" /> </Col>
|
||||||
|
<Col span=12>
|
||||||
|
<FieldFloat field=FormConfig.DiagramCount label="Diagram Count" />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Antd.Form>
|
||||||
|
</Form.Provider>
|
||||||
|
</Antd.Card>
|
||||||
|
</div>
|
||||||
|
<div> demoDist </div>
|
||||||
|
</div>
|
||||||
|
}
|
|
@ -1,180 +0,0 @@
|
||||||
// TODO: This setup is more confusing than it should be, there's more work to do in cleanup here.
|
|
||||||
module Inputs = {
|
|
||||||
module SamplingInputs = {
|
|
||||||
type t = {
|
|
||||||
sampleCount: option(int),
|
|
||||||
outputXYPoints: option(int),
|
|
||||||
kernelWidth: option(float),
|
|
||||||
shapeLength: option(int),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
let defaultRecommendedLength = 100;
|
|
||||||
let defaultShouldDownsample = true;
|
|
||||||
|
|
||||||
type inputs = {
|
|
||||||
squiggleString: string,
|
|
||||||
samplingInputs: SamplingInputs.t,
|
|
||||||
environment: ExpressionTypes.ExpressionTree.environment,
|
|
||||||
};
|
|
||||||
|
|
||||||
let empty: SamplingInputs.t = {
|
|
||||||
sampleCount: None,
|
|
||||||
outputXYPoints: None,
|
|
||||||
kernelWidth: None,
|
|
||||||
shapeLength: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let make =
|
|
||||||
(
|
|
||||||
~samplingInputs=empty,
|
|
||||||
~squiggleString,
|
|
||||||
~environment=ExpressionTypes.ExpressionTree.Environment.empty,
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
: inputs => {
|
|
||||||
samplingInputs,
|
|
||||||
squiggleString,
|
|
||||||
environment,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
type export = [
|
|
||||||
| `DistPlus(ProbExample.DistPlus.t)
|
|
||||||
| `Float(float)
|
|
||||||
| `Function(
|
|
||||||
(array(string), ProbExample.ExpressionTypes.ExpressionTree.node),
|
|
||||||
ProbExample.ExpressionTypes.ExpressionTree.environment,
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
module Internals = {
|
|
||||||
let addVariable =
|
|
||||||
(
|
|
||||||
{samplingInputs, squiggleString, environment}: Inputs.inputs,
|
|
||||||
str,
|
|
||||||
node,
|
|
||||||
)
|
|
||||||
: Inputs.inputs => {
|
|
||||||
samplingInputs,
|
|
||||||
squiggleString,
|
|
||||||
environment:
|
|
||||||
ExpressionTypes.ExpressionTree.Environment.update(environment, str, _ =>
|
|
||||||
Some(node)
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
type outputs = {
|
|
||||||
graph: ExpressionTypes.ExpressionTree.node,
|
|
||||||
shape: DistTypes.shape,
|
|
||||||
};
|
|
||||||
let makeOutputs = (graph, shape): outputs => {graph, shape};
|
|
||||||
|
|
||||||
let makeInputs =
|
|
||||||
(inputs: Inputs.inputs): ExpressionTypes.ExpressionTree.samplingInputs => {
|
|
||||||
sampleCount: inputs.samplingInputs.sampleCount |> E.O.default(10000),
|
|
||||||
outputXYPoints:
|
|
||||||
inputs.samplingInputs.outputXYPoints |> E.O.default(10000),
|
|
||||||
kernelWidth: inputs.samplingInputs.kernelWidth,
|
|
||||||
shapeLength: inputs.samplingInputs.shapeLength |> E.O.default(10000),
|
|
||||||
};
|
|
||||||
|
|
||||||
let runNode = (inputs, node) => {
|
|
||||||
ExpressionTree.toLeaf(makeInputs(inputs), inputs.environment, node);
|
|
||||||
};
|
|
||||||
|
|
||||||
let runProgram = (inputs: Inputs.inputs, p: ExpressionTypes.Program.program) => {
|
|
||||||
let ins = ref(inputs);
|
|
||||||
p
|
|
||||||
|> E.A.fmap(
|
|
||||||
fun
|
|
||||||
| `Assignment(name, node) => {
|
|
||||||
ins := addVariable(ins^, name, node);
|
|
||||||
None;
|
|
||||||
}
|
|
||||||
| `Expression(node) =>
|
|
||||||
Some(
|
|
||||||
runNode(ins^, node) |> E.R.fmap(r => (ins^.environment, r)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|> E.A.O.concatSomes
|
|
||||||
|> E.A.R.firstErrorOrOpen;
|
|
||||||
};
|
|
||||||
|
|
||||||
let inputsToLeaf = (inputs: Inputs.inputs) => {
|
|
||||||
MathJsParser.fromString(inputs.squiggleString)
|
|
||||||
|> E.R.bind(_, g => runProgram(inputs, g))
|
|
||||||
|> E.R.bind(_, r => E.A.last(r) |> E.O.toResult("No rendered lines"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let outputToDistPlus = (inputs: Inputs.inputs, shape: DistTypes.shape) => {
|
|
||||||
DistPlus.make(~shape, ~squiggleString=Some(inputs.squiggleString), ());
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let renderIfNeeded =
|
|
||||||
(inputs: Inputs.inputs, node: ExpressionTypes.ExpressionTree.node)
|
|
||||||
: result(ExpressionTypes.ExpressionTree.node, string) =>
|
|
||||||
node
|
|
||||||
|> (
|
|
||||||
fun
|
|
||||||
| `Normalize(_) as n
|
|
||||||
| `SymbolicDist(_) as n => {
|
|
||||||
`Render(n)
|
|
||||||
|> Internals.runNode(inputs)
|
|
||||||
|> (
|
|
||||||
fun
|
|
||||||
| Ok(`RenderedDist(_)) as r => r
|
|
||||||
| Error(r) => Error(r)
|
|
||||||
| _ => Error("Didn't render, but intended to")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
| n => Ok(n)
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: Consider using ExpressionTypes.ExpressionTree.getFloat or similar in this function
|
|
||||||
let coersionToExportedTypes =
|
|
||||||
(
|
|
||||||
inputs,
|
|
||||||
env: ProbExample.ExpressionTypes.ExpressionTree.environment,
|
|
||||||
node: ExpressionTypes.ExpressionTree.node,
|
|
||||||
)
|
|
||||||
: result(export, string) =>
|
|
||||||
node
|
|
||||||
|> renderIfNeeded(inputs)
|
|
||||||
|> E.R.bind(
|
|
||||||
_,
|
|
||||||
fun
|
|
||||||
| `RenderedDist(Discrete({xyShape: {xs: [|x|], ys: [|1.0|]}})) =>
|
|
||||||
Ok(`Float(x))
|
|
||||||
| `SymbolicDist(`Float(x)) => Ok(`Float(x))
|
|
||||||
| `RenderedDist(n) =>
|
|
||||||
Ok(`DistPlus(Internals.outputToDistPlus(inputs, n)))
|
|
||||||
| `Function(n) => Ok(`Function((n, env)))
|
|
||||||
| n =>
|
|
||||||
Error(
|
|
||||||
"Didn't output a rendered distribution. Format:"
|
|
||||||
++ ExpressionTree.toString(n),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
let evaluateProgram = (inputs: Inputs.inputs) => {
|
|
||||||
inputs
|
|
||||||
|> Internals.inputsToLeaf
|
|
||||||
|> E.R.bind(_, ((a, b)) => coersionToExportedTypes(inputs, a, b));
|
|
||||||
};
|
|
||||||
|
|
||||||
let evaluateFunction =
|
|
||||||
(
|
|
||||||
inputs: Inputs.inputs,
|
|
||||||
fn: (array(string), ExpressionTypes.ExpressionTree.node),
|
|
||||||
fnInputs,
|
|
||||||
) => {
|
|
||||||
let output =
|
|
||||||
ExpressionTree.runFunction(
|
|
||||||
Internals.makeInputs(inputs),
|
|
||||||
inputs.environment,
|
|
||||||
fnInputs,
|
|
||||||
fn,
|
|
||||||
);
|
|
||||||
output |> E.R.bind(_, coersionToExportedTypes(inputs, inputs.environment));
|
|
||||||
};
|
|
171
src/distPlus/ProgramEvaluator.res
Normal file
171
src/distPlus/ProgramEvaluator.res
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
// TODO: This setup is more confusing than it should be, there's more work to do in cleanup here.
|
||||||
|
module Inputs = {
|
||||||
|
module SamplingInputs = {
|
||||||
|
type t = {
|
||||||
|
sampleCount: option<int>,
|
||||||
|
outputXYPoints: option<int>,
|
||||||
|
kernelWidth: option<float>,
|
||||||
|
shapeLength: option<int>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let defaultRecommendedLength = 100
|
||||||
|
let defaultShouldDownsample = true
|
||||||
|
|
||||||
|
type inputs = {
|
||||||
|
squiggleString: string,
|
||||||
|
samplingInputs: SamplingInputs.t,
|
||||||
|
environment: ExpressionTypes.ExpressionTree.environment,
|
||||||
|
}
|
||||||
|
|
||||||
|
let empty: SamplingInputs.t = {
|
||||||
|
sampleCount: None,
|
||||||
|
outputXYPoints: None,
|
||||||
|
kernelWidth: None,
|
||||||
|
shapeLength: None,
|
||||||
|
}
|
||||||
|
|
||||||
|
let make = (
|
||||||
|
~samplingInputs=empty,
|
||||||
|
~squiggleString,
|
||||||
|
~environment=ExpressionTypes.ExpressionTree.Environment.empty,
|
||||||
|
(),
|
||||||
|
): inputs => {
|
||||||
|
samplingInputs: samplingInputs,
|
||||||
|
squiggleString: squiggleString,
|
||||||
|
environment: environment,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type \"export" = [
|
||||||
|
| #DistPlus(ProbExample.DistPlus.t)
|
||||||
|
| #Float(float)
|
||||||
|
| #Function(
|
||||||
|
(array<string>, ProbExample.ExpressionTypes.ExpressionTree.node),
|
||||||
|
ProbExample.ExpressionTypes.ExpressionTree.environment,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
module Internals = {
|
||||||
|
let addVariable = (
|
||||||
|
{samplingInputs, squiggleString, environment}: Inputs.inputs,
|
||||||
|
str,
|
||||||
|
node,
|
||||||
|
): Inputs.inputs => {
|
||||||
|
samplingInputs: samplingInputs,
|
||||||
|
squiggleString: squiggleString,
|
||||||
|
environment: ExpressionTypes.ExpressionTree.Environment.update(environment, str, _ => Some(
|
||||||
|
node,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
|
||||||
|
type outputs = {
|
||||||
|
graph: ExpressionTypes.ExpressionTree.node,
|
||||||
|
shape: DistTypes.shape,
|
||||||
|
}
|
||||||
|
let makeOutputs = (graph, shape): outputs => {graph: graph, shape: shape}
|
||||||
|
|
||||||
|
let makeInputs = (inputs: Inputs.inputs): ExpressionTypes.ExpressionTree.samplingInputs => {
|
||||||
|
sampleCount: inputs.samplingInputs.sampleCount |> E.O.default(10000),
|
||||||
|
outputXYPoints: inputs.samplingInputs.outputXYPoints |> E.O.default(10000),
|
||||||
|
kernelWidth: inputs.samplingInputs.kernelWidth,
|
||||||
|
shapeLength: inputs.samplingInputs.shapeLength |> E.O.default(10000),
|
||||||
|
}
|
||||||
|
|
||||||
|
let runNode = (inputs, node) =>
|
||||||
|
ExpressionTree.toLeaf(makeInputs(inputs), inputs.environment, node)
|
||||||
|
|
||||||
|
let runProgram = (inputs: Inputs.inputs, p: ExpressionTypes.Program.program) => {
|
||||||
|
let ins = ref(inputs)
|
||||||
|
p
|
||||||
|
|> E.A.fmap(x =>
|
||||||
|
switch x {
|
||||||
|
| #Assignment(name, node) =>
|
||||||
|
ins := addVariable(ins.contents, name, node)
|
||||||
|
None
|
||||||
|
| #Expression(node) =>
|
||||||
|
Some(runNode(ins.contents, node) |> E.R.fmap(r => (ins.contents.environment, r)))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|> E.A.O.concatSomes
|
||||||
|
|> E.A.R.firstErrorOrOpen
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputsToLeaf = (inputs: Inputs.inputs) =>
|
||||||
|
MathJsParser.fromString(inputs.squiggleString)
|
||||||
|
|> E.R.bind(_, g => runProgram(inputs, g))
|
||||||
|
|
||||||
|
let outputToDistPlus = (inputs: Inputs.inputs, shape: DistTypes.shape) =>
|
||||||
|
DistPlus.make(~shape, ~squiggleString=Some(inputs.squiggleString), ())
|
||||||
|
}
|
||||||
|
|
||||||
|
let renderIfNeeded = (inputs: Inputs.inputs, node: ExpressionTypes.ExpressionTree.node): result<
|
||||||
|
ExpressionTypes.ExpressionTree.node,
|
||||||
|
string,
|
||||||
|
> =>
|
||||||
|
node |> (
|
||||||
|
x =>
|
||||||
|
switch x {
|
||||||
|
| #Normalize(_) as n
|
||||||
|
| #SymbolicDist(_) as n =>
|
||||||
|
#Render(n)
|
||||||
|
|> Internals.runNode(inputs)
|
||||||
|
|> (
|
||||||
|
x =>
|
||||||
|
switch x {
|
||||||
|
| Ok(#RenderedDist(_)) as r => r
|
||||||
|
| Error(r) => Error(r)
|
||||||
|
| _ => Error("Didn't render, but intended to")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
| n => Ok(n)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: Consider using ExpressionTypes.ExpressionTree.getFloat or similar in this function
|
||||||
|
let coersionToExportedTypes = (
|
||||||
|
inputs,
|
||||||
|
env: ProbExample.ExpressionTypes.ExpressionTree.environment,
|
||||||
|
node: ExpressionTypes.ExpressionTree.node,
|
||||||
|
): result<\"export", string> =>
|
||||||
|
node
|
||||||
|
|> renderIfNeeded(inputs)
|
||||||
|
|> E.R.bind(_, x =>
|
||||||
|
switch x {
|
||||||
|
| #RenderedDist(Discrete({xyShape: {xs: [x], ys: [1.0]}})) => Ok(#Float(x))
|
||||||
|
| #SymbolicDist(#Float(x)) => Ok(#Float(x))
|
||||||
|
| #RenderedDist(n) => Ok(#DistPlus(Internals.outputToDistPlus(inputs, n)))
|
||||||
|
| #Function(n) => Ok(#Function(n, env))
|
||||||
|
| n => Error("Didn't output a rendered distribution. Format:" ++ ExpressionTree.toString(n))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
let rec mapM = (f, xs) =>
|
||||||
|
switch xs {
|
||||||
|
| list{} => Ok(list{})
|
||||||
|
| list{x, ...rest} =>
|
||||||
|
switch f(x) {
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
| Ok(val) =>
|
||||||
|
switch mapM(f, rest) {
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
| Ok(restList) => Ok(list{val, ...restList})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let evaluateProgram = (inputs: Inputs.inputs) =>
|
||||||
|
inputs |> Internals.inputsToLeaf |> E.R.bind(_, xs => mapM(((a, b)) => coersionToExportedTypes(inputs, a, b), (Array.to_list(xs))))
|
||||||
|
|
||||||
|
let evaluateFunction = (
|
||||||
|
inputs: Inputs.inputs,
|
||||||
|
fn: (array<string>, ExpressionTypes.ExpressionTree.node),
|
||||||
|
fnInputs,
|
||||||
|
) => {
|
||||||
|
let output = ExpressionTree.runFunction(
|
||||||
|
Internals.makeInputs(inputs),
|
||||||
|
inputs.environment,
|
||||||
|
fnInputs,
|
||||||
|
fn,
|
||||||
|
)
|
||||||
|
output |> E.R.bind(_, coersionToExportedTypes(inputs, inputs.environment))
|
||||||
|
}
|
|
@ -1382,6 +1382,11 @@
|
||||||
"@parcel/utils" "^1.11.0"
|
"@parcel/utils" "^1.11.0"
|
||||||
physical-cpu-count "^2.0.0"
|
physical-cpu-count "^2.0.0"
|
||||||
|
|
||||||
|
"@rescript/react@^0.10.3":
|
||||||
|
version "0.10.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rescript/react/-/react-0.10.3.tgz#a2a8bed6b017940ec26c2154764b350f50348889"
|
||||||
|
integrity sha512-Lf9rzrR3bQPKJjOK3PBRa/B3xrJ7CqQ1HYr9VHPVxJidarIJJFZBhj0Dg1uZURX+Wg/xiP0PHFxXmdj2bK8Vxw==
|
||||||
|
|
||||||
"@sinonjs/commons@^1.7.0":
|
"@sinonjs/commons@^1.7.0":
|
||||||
version "1.7.2"
|
version "1.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.2.tgz#505f55c74e0272b43f6c52d81946bed7058fc0e2"
|
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.2.tgz#505f55c74e0272b43f6c52d81946bed7058fc0e2"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user