@elaraai/e3-ui-components 1.0.22 → 1.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/diff/index.d.ts.map +1 -1
- package/dist/experiment/derive.d.ts +5 -3
- package/dist/experiment/derive.d.ts.map +1 -1
- package/dist/experiment/index.d.ts.map +1 -1
- package/dist/index.cjs +153 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +154 -83
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
package/dist/index.js
CHANGED
|
@@ -27,9 +27,8 @@ import { jsx as jsx$1, Fragment, jsxs } from "react/jsx-runtime";
|
|
|
27
27
|
import * as React from "react";
|
|
28
28
|
import React__default, { useId, useMemo, useContext, createContext, useRef, useEffect, useState, useCallback, useSyncExternalStore, memo, forwardRef, useLayoutEffect, Fragment as Fragment$1, Component } from "react";
|
|
29
29
|
import { Box, Flex, Text, HStack, Input, useSlotRecipe, useRecipe, VStack, useToken, Drawer, Portal, Field, NativeSelect, Textarea, chakra, Tooltip, SegmentGroup, Menu, HoverCard, useChakraContext, Spinner, Code, Clipboard, IconButton, Badge, Button, Tabs, useTabs } from "@chakra-ui/react";
|
|
30
|
-
import { implementUIComponent, getSomeorUndefined, SliceEditPopover, SlicePredicateBuilder,
|
|
30
|
+
import { implementUIComponent, getSomeorUndefined, formatPredicate, SliceEditPopover, SlicePredicateBuilder, StateRuntime, buildSliceHandle, DEFAULT_SLICE_STATE, registerPlatformImplementation as registerPlatformImplementation$1, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, formatTick, useSliceReactivity, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, OverlayImpl, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
|
|
31
31
|
import { createPortal } from "react-dom";
|
|
32
|
-
import "@elaraai/e3-ui";
|
|
33
32
|
import { sliceMatches } from "@elaraai/east-ui/internal";
|
|
34
33
|
import { QueryClient as QueryClient$1, QueryClientProvider, useMutation, useQuery } from "@tanstack/react-query";
|
|
35
34
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
@@ -8372,6 +8371,7 @@ function useDatasetKeyVersions(workspace, paths) {
|
|
|
8372
8371
|
);
|
|
8373
8372
|
return useSyncExternalStore(subscribe, getSnapshot);
|
|
8374
8373
|
}
|
|
8374
|
+
const warnedDirectNoPatch = /* @__PURE__ */ new Set();
|
|
8375
8375
|
function pickCommitKind(mode, patchPath) {
|
|
8376
8376
|
if (mode === "staged" && !patchPath) return "apply-buffer-to-source";
|
|
8377
8377
|
if (mode === "staged" && patchPath) return "publish-buffer-to-patch";
|
|
@@ -8389,7 +8389,16 @@ function deriveBindings(workspace, bindings) {
|
|
|
8389
8389
|
const types = getBindingTypes(workspace, sourcePath);
|
|
8390
8390
|
if (!types) continue;
|
|
8391
8391
|
const commitKind = pickCommitKind(mode, patchPath);
|
|
8392
|
-
if (!commitKind)
|
|
8392
|
+
if (!commitKind) {
|
|
8393
|
+
const key = datasetPathToString(sourcePath);
|
|
8394
|
+
if (!warnedDirectNoPatch.has(key)) {
|
|
8395
|
+
warnedDirectNoPatch.add(key);
|
|
8396
|
+
console.warn(
|
|
8397
|
+
`[Diff] binding "${key}" is mode="direct" with no patch dataset — it writes through immediately, so the Diff has nothing to review. Pass { mode: "staged" } to Data.bind (or give it a patch dataset) to surface its edits here.`
|
|
8398
|
+
);
|
|
8399
|
+
}
|
|
8400
|
+
continue;
|
|
8401
|
+
}
|
|
8393
8402
|
const sourceType = types.sourceType;
|
|
8394
8403
|
const patchType = types.patchType;
|
|
8395
8404
|
const label = formatBindingLabel(sourcePath);
|
|
@@ -60709,9 +60718,28 @@ function DeckSkeleton({ tab }) {
|
|
|
60709
60718
|
] })
|
|
60710
60719
|
] });
|
|
60711
60720
|
}
|
|
60721
|
+
function LoadingSkeleton() {
|
|
60722
|
+
const sk = useRecipe({ key: "skeleton" });
|
|
60723
|
+
const line2 = (w2, h2) => /* @__PURE__ */ jsx$1(Box, { css: sk({ variant: "line" }), width: w2, height: h2 });
|
|
60724
|
+
const block = (h2) => /* @__PURE__ */ jsx$1(Box, { css: sk({ variant: "block" }), width: "100%", minHeight: h2 });
|
|
60725
|
+
return /* @__PURE__ */ jsxs(Box, { layerStyle: "frame", overflow: "visible", children: [
|
|
60726
|
+
/* @__PURE__ */ jsxs(Box, { layerStyle: "header.bar", display: "flex", alignItems: "center", gap: "3.5", children: [
|
|
60727
|
+
line2("260px", "20px"),
|
|
60728
|
+
/* @__PURE__ */ jsx$1(Box, { flex: "1" }),
|
|
60729
|
+
line2("72px", "16px")
|
|
60730
|
+
] }),
|
|
60731
|
+
/* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: "304px minmax(0,1fr)", alignItems: "start", children: [
|
|
60732
|
+
/* @__PURE__ */ jsx$1(Box, { borderRightWidth: "1px", borderColor: "border.subtle", p: "4.5", display: "flex", flexDirection: "column", gap: "5", children: [0, 1, 2, 3].map((n2) => /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", gap: "2", children: [
|
|
60733
|
+
line2("150px", "12px"),
|
|
60734
|
+
block("40px")
|
|
60735
|
+
] }, n2)) }),
|
|
60736
|
+
/* @__PURE__ */ jsx$1(DeckSkeleton, { tab: "answer" })
|
|
60737
|
+
] })
|
|
60738
|
+
] });
|
|
60739
|
+
}
|
|
60712
60740
|
const experimentValueEqual = equalFor(Experiment.Component.schema);
|
|
60713
60741
|
const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
60714
|
-
var _a2, _b2, _c2
|
|
60742
|
+
var _a2, _b2, _c2;
|
|
60715
60743
|
const v3 = value;
|
|
60716
60744
|
const button = useRecipe({ key: "button" });
|
|
60717
60745
|
const chip = useRecipe({ key: "chip" });
|
|
@@ -60721,27 +60749,48 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60721
60749
|
const es = useSlotRecipe({ key: "eyebrowRow" })({});
|
|
60722
60750
|
const workspace = getReactiveDatasetCache().getConfig().workspace ?? "";
|
|
60723
60751
|
const data4 = useBindingValue(v3.data);
|
|
60724
|
-
const configBind = useBindingValue(v3.config);
|
|
60725
60752
|
const journalBind = useBindingValue(v3.journal.type === "some" ? v3.journal.value : null);
|
|
60726
|
-
const populationBind = useBindingValue(v3.population.type === "some" ? v3.population.value : null);
|
|
60727
60753
|
const meta3 = getSomeorUndefined(v3.columnMeta);
|
|
60728
60754
|
const readonly = getSomeorUndefined(v3.readonly) ?? false;
|
|
60729
|
-
const
|
|
60730
|
-
const
|
|
60731
|
-
const
|
|
60755
|
+
const configsBind = useBindingValue(v3.configs);
|
|
60756
|
+
const configs = useMemo(() => configsBind.value ?? [], [configsBind.value]);
|
|
60757
|
+
const [currentConfigId, setCurrentConfigId] = useState(void 0);
|
|
60758
|
+
const selectedEntry = useMemo(
|
|
60759
|
+
() => configs.find((c2) => c2.id === currentConfigId) ?? configs[0],
|
|
60760
|
+
[configs, currentConfigId]
|
|
60761
|
+
);
|
|
60762
|
+
useEffect(() => {
|
|
60763
|
+
const first2 = configs[0];
|
|
60764
|
+
if (currentConfigId === void 0 && first2 !== void 0) setCurrentConfigId(first2.id);
|
|
60765
|
+
}, [configs, currentConfigId]);
|
|
60766
|
+
const configGroups = useMemo(() => {
|
|
60732
60767
|
const buckets = /* @__PURE__ */ new Map();
|
|
60733
|
-
for (const
|
|
60734
|
-
const label = getSomeorUndefined(
|
|
60768
|
+
for (const c2 of configs) {
|
|
60769
|
+
const label = getSomeorUndefined(c2.group) ?? "Questions";
|
|
60735
60770
|
const bucket = buckets.get(label);
|
|
60736
|
-
if (bucket) bucket.push(
|
|
60737
|
-
else buckets.set(label, [
|
|
60771
|
+
if (bucket) bucket.push(c2);
|
|
60772
|
+
else buckets.set(label, [c2]);
|
|
60738
60773
|
}
|
|
60739
60774
|
return [...buckets].map(([label, items]) => ({ label, items }));
|
|
60740
|
-
}, [
|
|
60775
|
+
}, [configs]);
|
|
60741
60776
|
const { columns, rowArrayType } = useColumns(workspace, v3.data.source);
|
|
60742
|
-
const
|
|
60777
|
+
const [workingConfig, setWorkingConfig] = useState(void 0);
|
|
60743
60778
|
const [localPop, setLocalPop] = useState([]);
|
|
60744
|
-
const
|
|
60779
|
+
const [stale, setStale] = useState(false);
|
|
60780
|
+
const seededIdRef = useRef(void 0);
|
|
60781
|
+
useEffect(() => {
|
|
60782
|
+
const id3 = selectedEntry == null ? void 0 : selectedEntry.id;
|
|
60783
|
+
if (id3 === seededIdRef.current) return;
|
|
60784
|
+
const switching = seededIdRef.current !== void 0;
|
|
60785
|
+
seededIdRef.current = id3;
|
|
60786
|
+
setWorkingConfig(selectedEntry == null ? void 0 : selectedEntry.spec);
|
|
60787
|
+
setLocalPop(getSomeorUndefined(selectedEntry == null ? void 0 : selectedEntry.population) ?? []);
|
|
60788
|
+
const precomputed = (selectedEntry == null ? void 0 : selectedEntry.result.type) === "some";
|
|
60789
|
+
const hasEstimator = v3.experiment.type === "some";
|
|
60790
|
+
setStale(switching && hasEstimator && !precomputed);
|
|
60791
|
+
}, [selectedEntry, v3.experiment.type]);
|
|
60792
|
+
const config2 = workingConfig;
|
|
60793
|
+
const population = localPop;
|
|
60745
60794
|
const filteredRows = useMemo(() => {
|
|
60746
60795
|
if (!data4.value) return null;
|
|
60747
60796
|
return population.length ? data4.value.filter((r2) => rowMatchesAll(r2, population)) : data4.value;
|
|
@@ -60758,7 +60807,9 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60758
60807
|
[columns, meta3]
|
|
60759
60808
|
);
|
|
60760
60809
|
const estInputs = useMemo(() => rowArrayType ? [rowArrayType, Experiment.Types.Config] : null, [rowArrayType]);
|
|
60761
|
-
const experiment = useFuncCall(v3.experiment.name, estInputs, Experiment.Types.Result);
|
|
60810
|
+
const experiment = useFuncCall(v3.experiment.type === "some" ? v3.experiment.value.name : null, estInputs, Experiment.Types.Result);
|
|
60811
|
+
const hasExperiment = v3.experiment.type === "some";
|
|
60812
|
+
const shownResult = experiment.result ?? getSomeorUndefined(selectedEntry == null ? void 0 : selectedEntry.result) ?? null;
|
|
60762
60813
|
const hasDesign = v3.design.type === "some";
|
|
60763
60814
|
const designInputs = useMemo(
|
|
60764
60815
|
() => rowArrayType ? [rowArrayType, Experiment.Types.Config, Experiment.Types.Result, Experiment.Types.DesignConfig] : null,
|
|
@@ -60773,8 +60824,13 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60773
60824
|
experiment.call(filteredRows, config2);
|
|
60774
60825
|
}, [filteredRows, config2, experiment]);
|
|
60775
60826
|
const autoRan = useRef(false);
|
|
60827
|
+
const hasPrecomputed = selectedEntry !== void 0 && selectedEntry.result.type === "some";
|
|
60776
60828
|
useEffect(() => {
|
|
60777
60829
|
if (autoRan.current) return;
|
|
60830
|
+
if (hasPrecomputed || !hasExperiment) {
|
|
60831
|
+
autoRan.current = true;
|
|
60832
|
+
return;
|
|
60833
|
+
}
|
|
60778
60834
|
if (!filteredRows || !config2 || !rowArrayType) return;
|
|
60779
60835
|
if (experiment.result !== null || experiment.status === "running") {
|
|
60780
60836
|
autoRan.current = true;
|
|
@@ -60784,29 +60840,23 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60784
60840
|
autoRan.current = true;
|
|
60785
60841
|
if (filteredRows.length > AUTORUN_MAX_ROWS) return;
|
|
60786
60842
|
runAll();
|
|
60787
|
-
}, [filteredRows, config2, rowArrayType, experiment.result, experiment.status, runAll]);
|
|
60843
|
+
}, [hasPrecomputed, hasExperiment, filteredRows, config2, rowArrayType, experiment.result, experiment.status, runAll]);
|
|
60788
60844
|
useEffect(() => {
|
|
60789
60845
|
if (experiment.result !== null) setRanConfig(pendingConfigRef.current);
|
|
60790
60846
|
}, [experiment.result]);
|
|
60791
|
-
const
|
|
60792
|
-
const editConfig = useCallback((next2, fromPreset) => {
|
|
60793
|
-
if (readonly) return;
|
|
60794
|
-
setStale(true);
|
|
60795
|
-
setCurrentPreset(fromPreset);
|
|
60796
|
-
queueMicrotask(() => configBind.mutate(next2));
|
|
60797
|
-
}, [readonly, configBind]);
|
|
60798
|
-
const editPopulation = useCallback((next2, fromPreset) => {
|
|
60847
|
+
const editConfig = useCallback((next2) => {
|
|
60799
60848
|
if (readonly) return;
|
|
60800
|
-
setStale(true);
|
|
60801
|
-
|
|
60802
|
-
|
|
60803
|
-
|
|
60804
|
-
}, [readonly, v3.population.type, populationBind]);
|
|
60805
|
-
const selectPreset = useCallback((p2) => {
|
|
60849
|
+
if (v3.experiment.type === "some") setStale(true);
|
|
60850
|
+
setWorkingConfig(next2);
|
|
60851
|
+
}, [readonly, v3.experiment.type]);
|
|
60852
|
+
const editPopulation = useCallback((next2) => {
|
|
60806
60853
|
if (readonly) return;
|
|
60807
|
-
|
|
60808
|
-
|
|
60809
|
-
}, [readonly,
|
|
60854
|
+
if (v3.experiment.type === "some") setStale(true);
|
|
60855
|
+
setLocalPop(next2);
|
|
60856
|
+
}, [readonly, v3.experiment.type]);
|
|
60857
|
+
const selectEntry = useCallback((c2) => {
|
|
60858
|
+
setCurrentConfigId(c2.id);
|
|
60859
|
+
}, []);
|
|
60810
60860
|
const onRun = useCallback(() => {
|
|
60811
60861
|
runAll();
|
|
60812
60862
|
setStale(false);
|
|
@@ -60821,18 +60871,16 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60821
60871
|
adjusted: r2.adjusted.type === "some" ? some(r2.adjusted.value.effect) : none$1,
|
|
60822
60872
|
committed_at: /* @__PURE__ */ new Date(),
|
|
60823
60873
|
committed_by: "you",
|
|
60824
|
-
// Record which
|
|
60825
|
-
preset:
|
|
60874
|
+
// Record which question framed this experiment.
|
|
60875
|
+
preset: currentConfigId !== void 0 ? some(currentConfigId) : none$1
|
|
60826
60876
|
};
|
|
60827
60877
|
journalBind.mutate([row, ...journalBind.value ?? []]);
|
|
60828
60878
|
try {
|
|
60829
60879
|
await journalBind.commit();
|
|
60830
|
-
await configBind.commit();
|
|
60831
|
-
if (v3.population.type === "some") await populationBind.commit();
|
|
60832
60880
|
setStale(false);
|
|
60833
60881
|
} catch {
|
|
60834
60882
|
}
|
|
60835
|
-
}, [config2, experiment.result, journalBind,
|
|
60883
|
+
}, [config2, experiment.result, journalBind, currentConfigId]);
|
|
60836
60884
|
const [tab, setTab] = useState(((_a2 = getSomeorUndefined(v3.defaultTab)) == null ? void 0 : _a2.type) ?? "answer");
|
|
60837
60885
|
const [guidance, setGuidance] = useState(true);
|
|
60838
60886
|
const now2 = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
@@ -60847,39 +60895,44 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60847
60895
|
}, [ranConfig, config2, meta3]);
|
|
60848
60896
|
const view = useMemo(() => {
|
|
60849
60897
|
if (!config2) return null;
|
|
60850
|
-
return deriveView(config2, ranConfig ?? config2, columns,
|
|
60851
|
-
}, [config2, ranConfig, columns,
|
|
60898
|
+
return deriveView(config2, ranConfig ?? config2, columns, shownResult, journalBind.value, meta3, nRows, now2);
|
|
60899
|
+
}, [config2, ranConfig, columns, shownResult, journalBind.value, meta3, nRows, now2]);
|
|
60852
60900
|
const designConfigValue = useMemo(() => ({
|
|
60853
60901
|
alpha: none$1,
|
|
60854
60902
|
target_power: none$1,
|
|
60855
60903
|
materiality: none$1,
|
|
60856
60904
|
treated_shares: some([0.5, 0.3])
|
|
60857
60905
|
}), []);
|
|
60906
|
+
const precomputedDesign = getSomeorUndefined(selectedEntry == null ? void 0 : selectedEntry.design) ?? null;
|
|
60858
60907
|
const designSnapRef = useRef(null);
|
|
60859
60908
|
useEffect(() => {
|
|
60860
60909
|
var _a3;
|
|
60861
|
-
if (tab !== "validate" || !hasDesign || design.pending) return;
|
|
60862
|
-
if (!filteredRows || !config2 || !
|
|
60863
|
-
if (((_a3 = designSnapRef.current) == null ? void 0 : _a3.result) ===
|
|
60864
|
-
designSnapRef.current = { result:
|
|
60865
|
-
design.call(filteredRows, ranConfig ?? config2,
|
|
60866
|
-
}, [tab, hasDesign, filteredRows, config2, ranConfig,
|
|
60867
|
-
const vmDesign = useMemo(
|
|
60868
|
-
(
|
|
60869
|
-
|
|
60870
|
-
);
|
|
60871
|
-
const designFresh = design.result !== null && ((_b2 = designSnapRef.current) == null ? void 0 : _b2.result) ===
|
|
60910
|
+
if (tab !== "validate" || !hasDesign || design.pending || precomputedDesign !== null) return;
|
|
60911
|
+
if (!filteredRows || !config2 || !shownResult) return;
|
|
60912
|
+
if (((_a3 = designSnapRef.current) == null ? void 0 : _a3.result) === shownResult) return;
|
|
60913
|
+
designSnapRef.current = { result: shownResult, config: ranConfig ?? config2 };
|
|
60914
|
+
design.call(filteredRows, ranConfig ?? config2, shownResult, designConfigValue);
|
|
60915
|
+
}, [tab, hasDesign, precomputedDesign, filteredRows, config2, ranConfig, shownResult, design, designConfigValue]);
|
|
60916
|
+
const vmDesign = useMemo(() => {
|
|
60917
|
+
if (precomputedDesign !== null && shownResult !== null && config2) return deriveDesign(precomputedDesign, shownResult, ranConfig ?? config2, meta3);
|
|
60918
|
+
return design.result && designSnapRef.current ? deriveDesign(design.result, designSnapRef.current.result, designSnapRef.current.config, meta3) : null;
|
|
60919
|
+
}, [precomputedDesign, shownResult, config2, ranConfig, design.result, meta3]);
|
|
60920
|
+
const designFresh = precomputedDesign !== null && shownResult !== null || design.result !== null && ((_b2 = designSnapRef.current) == null ? void 0 : _b2.result) === shownResult && !design.pending;
|
|
60872
60921
|
if (!config2 || !view) {
|
|
60873
60922
|
const failed2 = experiment.status === "failed";
|
|
60874
|
-
const
|
|
60875
|
-
const
|
|
60923
|
+
const noConfigs = !configsBind.error && configs.length === 0;
|
|
60924
|
+
const which = data4.error ? "dataset" : configsBind.error ? "configs" : journalBind.error ? "journal" : null;
|
|
60925
|
+
const bindError = data4.error ?? configsBind.error ?? journalBind.error;
|
|
60876
60926
|
const bindMsg = bindError instanceof Error ? bindError.message : bindError != null ? String(bindError) : null;
|
|
60877
|
-
return /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame", p: "6", children:
|
|
60927
|
+
if (bindMsg) return /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame", p: "6", children: /* @__PURE__ */ jsxs(Text, { textStyle: "body.sm", color: "fg.danger", children: [
|
|
60878
60928
|
"Couldn’t load the experiment ",
|
|
60879
60929
|
which,
|
|
60880
60930
|
": ",
|
|
60881
60931
|
bindMsg
|
|
60882
|
-
] })
|
|
60932
|
+
] }) });
|
|
60933
|
+
if (noConfigs) return /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame", p: "6", children: /* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", color: "fg.muted", children: "No questions to show — bind a non-empty configs list." }) });
|
|
60934
|
+
if (failed2 && experiment.error) return /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame", p: "6", children: /* @__PURE__ */ jsx$1(RunError, { error: experiment.error }) });
|
|
60935
|
+
return /* @__PURE__ */ jsx$1(LoadingSkeleton, {});
|
|
60883
60936
|
}
|
|
60884
60937
|
const { spec: vs, answer: a2, refusal: ref, overlap: ov, refute: vr, dose: vd, journal, verdict } = view;
|
|
60885
60938
|
const higherBetter = getSomeorUndefined((_c2 = meta3 == null ? void 0 : meta3.get(vs.outcome)) == null ? void 0 : _c2.higherIsBetter);
|
|
@@ -60889,18 +60942,19 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60889
60942
|
/* @__PURE__ */ jsx$1(Box, { css: bs.track, children: /* @__PURE__ */ jsx$1(Box, { css: bs.fill, width: `${Math.round(r2.frac * 100)}%`, bg: toneToken(r2.tone) }) }),
|
|
60890
60943
|
/* @__PURE__ */ jsx$1(Text, { css: bs.value, children: r2.value })
|
|
60891
60944
|
] }, i)) });
|
|
60892
|
-
const specStaged = configBind.mode === "staged";
|
|
60893
60945
|
const hasJournal = v3.journal.type === "some";
|
|
60894
|
-
const canRun = !readonly;
|
|
60895
|
-
const canCommit = !readonly &&
|
|
60946
|
+
const canRun = !readonly && hasExperiment;
|
|
60947
|
+
const canCommit = !readonly && hasExperiment && hasJournal;
|
|
60896
60948
|
const runDisabled = !data4.value || experiment.pending;
|
|
60897
60949
|
const commitDisabled = experiment.status !== "succeeded" || experiment.pending || stale;
|
|
60898
60950
|
const failed = experiment.status === "failed" && experiment.error;
|
|
60899
|
-
const showResult =
|
|
60900
|
-
const
|
|
60951
|
+
const showResult = shownResult !== null && !experiment.pending && !failed;
|
|
60952
|
+
const anyPrecomputedDesign = configs.some((c2) => c2.design.type === "some");
|
|
60953
|
+
const showValidate = hasDesign || anyPrecomputedDesign;
|
|
60954
|
+
const tabKeys = [...["answer", "trust", "dose"], ...showValidate ? ["validate"] : []];
|
|
60901
60955
|
return /* @__PURE__ */ jsx$1(GuidanceProvider, { on: guidance, vars: helpVars, children: /* @__PURE__ */ jsxs(Box, { layerStyle: "frame", overflow: "visible", children: [
|
|
60902
60956
|
/* @__PURE__ */ jsxs(Box, { layerStyle: "header.bar", display: "flex", alignItems: "center", gap: "3.5", children: [
|
|
60903
|
-
|
|
60957
|
+
configs.length > 1 ? /* @__PURE__ */ jsxs(Menu.Root, { children: [
|
|
60904
60958
|
/* @__PURE__ */ jsx$1(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(Box, { as: "button", bg: "transparent", border: "0", p: "0", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: "2", textAlign: "start", children: [
|
|
60905
60959
|
/* @__PURE__ */ jsxs(Text, { textStyle: "title.card", color: "fg.muted", children: [
|
|
60906
60960
|
"Does ",
|
|
@@ -60911,12 +60965,12 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60911
60965
|
] }),
|
|
60912
60966
|
/* @__PURE__ */ jsx$1(Box, { as: "span", color: "fg.subtle", fontSize: "11px", lineHeight: "1", children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faChevronDown }) })
|
|
60913
60967
|
] }) }),
|
|
60914
|
-
/* @__PURE__ */ jsx$1(Portal, { children: /* @__PURE__ */ jsx$1(Menu.Positioner, { children: /* @__PURE__ */ jsx$1(Menu.Content, { minW: "280px", children:
|
|
60915
|
-
g2.label !== "
|
|
60916
|
-
g2.items.map((
|
|
60917
|
-
/* @__PURE__ */ jsx$1(Box, { as: "span", width: "14px", flexShrink: "0", color: "brand.fg", children:
|
|
60918
|
-
|
|
60919
|
-
] },
|
|
60968
|
+
/* @__PURE__ */ jsx$1(Portal, { children: /* @__PURE__ */ jsx$1(Menu.Positioner, { children: /* @__PURE__ */ jsx$1(Menu.Content, { minW: "280px", children: configGroups.map((g2) => /* @__PURE__ */ jsxs(Menu.ItemGroup, { children: [
|
|
60969
|
+
g2.label !== "Questions" && /* @__PURE__ */ jsx$1(Menu.ItemGroupLabel, { textStyle: "caption.eyebrow", fontSize: "9px", children: g2.label }),
|
|
60970
|
+
g2.items.map((c2) => /* @__PURE__ */ jsxs(Menu.Item, { value: c2.id, onClick: () => selectEntry(c2), gap: "2", children: [
|
|
60971
|
+
/* @__PURE__ */ jsx$1(Box, { as: "span", width: "14px", flexShrink: "0", color: "brand.fg", children: c2.id === (selectedEntry == null ? void 0 : selectedEntry.id) && /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faCheck, style: { fontSize: "10px" } }) }),
|
|
60972
|
+
c2.label
|
|
60973
|
+
] }, c2.id))
|
|
60920
60974
|
] }, g2.label)) }) }) })
|
|
60921
60975
|
] }) : /* @__PURE__ */ jsx$1(Text, { textStyle: "title.card", color: "fg.muted", children: /* @__PURE__ */ jsxs(Help, { id: "header", children: [
|
|
60922
60976
|
"Does ",
|
|
@@ -60926,6 +60980,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60926
60980
|
"?"
|
|
60927
60981
|
] }) }),
|
|
60928
60982
|
/* @__PURE__ */ jsx$1(Box, { flex: "1" }),
|
|
60983
|
+
readonly && /* @__PURE__ */ jsx$1(Box, { as: "span", css: badge({ variant: "plain", size: "sm" }), textTransform: "none", letterSpacing: "normal", children: "View only" }),
|
|
60929
60984
|
/* @__PURE__ */ jsxs(Box, { as: "span", css: dataStatus.root, children: [
|
|
60930
60985
|
/* @__PURE__ */ jsx$1(Box, { as: "span", css: dataStatus.indicator }),
|
|
60931
60986
|
/* @__PURE__ */ jsx$1(Box, { as: "span", css: dataStatus.label, children: stale ? `${nRows} rows` : vs.dataLabel })
|
|
@@ -60937,15 +60992,15 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60937
60992
|
/* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: "304px minmax(0,1fr)", alignItems: "start", children: [
|
|
60938
60993
|
/* @__PURE__ */ jsxs(Box, { borderRightWidth: "1px", borderColor: "border.subtle", children: [
|
|
60939
60994
|
/* @__PURE__ */ jsxs(Step, { n: 1, title: "What did you change?", help: "step_treatment", children: [
|
|
60940
|
-
/* @__PURE__ */ jsx$1(ColumnPick, { column: vs.treatment, kind: vs.treatmentKind, badge, button, choices: columns.filter((c2) => c2.kind === "boolean" || c2.kind === "integer").map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, treatment: c2 }) }),
|
|
60995
|
+
/* @__PURE__ */ jsx$1(ColumnPick, { column: vs.treatment, kind: vs.treatmentKind, badge, button, readonly, choices: columns.filter((c2) => c2.kind === "boolean" || c2.kind === "integer").map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, treatment: c2 }) }),
|
|
60941
60996
|
/* @__PURE__ */ jsxs(Text, { textStyle: "caption", mt: "1.5", children: [
|
|
60942
60997
|
"Treated = ",
|
|
60943
60998
|
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: vs.comparison })
|
|
60944
60999
|
] })
|
|
60945
61000
|
] }),
|
|
60946
|
-
/* @__PURE__ */ jsx$1(Step, { n: 2, title: "What did you want it to improve?", help: "step_outcome", children: /* @__PURE__ */ jsx$1(ColumnPick, { column: vs.outcome, kind: vs.outcomeKind, badge, button, choices: columns.filter((c2) => c2.kind === "float" || c2.kind === "integer").map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, outcome: c2 }) }) }),
|
|
61001
|
+
/* @__PURE__ */ jsx$1(Step, { n: 2, title: "What did you want it to improve?", help: "step_outcome", children: /* @__PURE__ */ jsx$1(ColumnPick, { column: vs.outcome, kind: vs.outcomeKind, badge, button, readonly, choices: columns.filter((c2) => c2.kind === "float" || c2.kind === "integer").map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, outcome: c2 }) }) }),
|
|
60947
61002
|
/* @__PURE__ */ jsx$1(Step, { n: 3, title: "What else was different?", help: "step_confounders", children: /* @__PURE__ */ jsxs(Box, { layerStyle: "frame.flat", children: [
|
|
60948
|
-
/* @__PURE__ */ jsx$1(Box, { maxH: "216px", overflowY: "auto", children: vs.confounders.map((c2, i) => /* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: "1fr 78px 16px", gap: "2.5", alignItems: "center", px: "2.5", py: "2.5", borderTopWidth: i ? "1px" : "0", borderColor: "border.subtle", children: [
|
|
61003
|
+
/* @__PURE__ */ jsx$1(Box, { maxH: "216px", overflowY: "auto", children: vs.confounders.map((c2, i) => /* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: readonly ? "1fr 78px" : "1fr 78px 16px", gap: "2.5", alignItems: "center", px: "2.5", py: "2.5", borderTopWidth: i ? "1px" : "0", borderColor: "border.subtle", children: [
|
|
60949
61004
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
60950
61005
|
/* @__PURE__ */ jsx$1(Text, { textStyle: "mono.sm", fontWeight: "semibold", color: "fg.default", children: c2.col }),
|
|
60951
61006
|
/* @__PURE__ */ jsx$1(Text, { textStyle: "caption", lineHeight: "1.35", mt: "px", children: c2.reason })
|
|
@@ -60954,14 +61009,14 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60954
61009
|
/* @__PURE__ */ jsx$1(Box, { css: bs.track, children: /* @__PURE__ */ jsx$1(Box, { css: bs.fill, width: `${Math.round(c2.imbalance * 100)}%`, bg: toneToken(c2.tone) }) }),
|
|
60955
61010
|
/* @__PURE__ */ jsx$1(Text, { textStyle: "caption.eyebrow", fontSize: "9px", textAlign: "center", mt: "1.5", children: /* @__PURE__ */ jsx$1(Help, { id: "confounder_imbalance", children: c2.level }) })
|
|
60956
61011
|
] }),
|
|
60957
|
-
/* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "ghost", size: "xs" }), px: "0", minW: "16px", display: "inline-flex", alignItems: "center", justifyContent: "center", "aria-label": `Remove ${c2.col}`, onClick: () => editConfig({ ...config2, common_causes: config2.common_causes.filter((x2) => x2 !== c2.col), categorical: config2.categorical.type === "some" ? some(config2.categorical.value.filter((x2) => x2 !== c2.col)) : none$1 }), children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faXmark, style: { fontSize: "11px" } }) })
|
|
61012
|
+
!readonly && /* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "ghost", size: "xs" }), px: "0", minW: "16px", display: "inline-flex", alignItems: "center", justifyContent: "center", "aria-label": `Remove ${c2.col}`, onClick: () => editConfig({ ...config2, common_causes: config2.common_causes.filter((x2) => x2 !== c2.col), categorical: config2.categorical.type === "some" ? some(config2.categorical.value.filter((x2) => x2 !== c2.col)) : none$1 }), children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faXmark, style: { fontSize: "11px" } }) })
|
|
60958
61013
|
] }, i)) }),
|
|
60959
|
-
vs.suggestion && /* @__PURE__ */ jsx$1(ColumnMenu, { choices: columns.filter((c2) => !(/* @__PURE__ */ new Set([config2.treatment, config2.outcome, ...config2.common_causes])).has(c2.name)).map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, common_causes: [...config2.common_causes, c2] }), children: /* @__PURE__ */ jsxs(Box, { as: "button", css: button({ variant: "ghost", size: "sm" }), justifyContent: "flex-start", width: "100%", color: "brand.fg", fontFamily: "mono", display: "inline-flex", alignItems: "center", gap: "2", children: [
|
|
61014
|
+
!readonly && vs.suggestion && /* @__PURE__ */ jsx$1(ColumnMenu, { choices: columns.filter((c2) => !(/* @__PURE__ */ new Set([config2.treatment, config2.outcome, ...config2.common_causes])).has(c2.name)).map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, common_causes: [...config2.common_causes, c2] }), children: /* @__PURE__ */ jsxs(Box, { as: "button", css: button({ variant: "ghost", size: "sm" }), justifyContent: "flex-start", width: "100%", color: "brand.fg", fontFamily: "mono", display: "inline-flex", alignItems: "center", gap: "2", children: [
|
|
60960
61015
|
/* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faPlus, style: { fontSize: "9px" } }),
|
|
60961
61016
|
"add another"
|
|
60962
61017
|
] }) })
|
|
60963
61018
|
] }) }),
|
|
60964
|
-
/* @__PURE__ */ jsx$1(Step, { n: 4, title: `Which ${SUBJECT_MANY}?`, help: "step_population", children: /* @__PURE__ */ jsx$1(FilterRail, { fields, population, onChange: editPopulation, chip, button }) }),
|
|
61019
|
+
/* @__PURE__ */ jsx$1(Step, { n: 4, title: `Which ${SUBJECT_MANY}?`, help: "step_population", children: /* @__PURE__ */ jsx$1(FilterRail, { fields, population, onChange: editPopulation, chip, button, readonly }) }),
|
|
60965
61020
|
/* @__PURE__ */ jsxs(Box, { as: "details", borderTopWidth: "1px", borderColor: "border.subtle", children: [
|
|
60966
61021
|
/* @__PURE__ */ jsxs(
|
|
60967
61022
|
Box,
|
|
@@ -60994,8 +61049,8 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
60994
61049
|
}
|
|
60995
61050
|
),
|
|
60996
61051
|
/* @__PURE__ */ jsxs(Box, { px: "4.5", pb: "3.5", pt: "0.5", children: [
|
|
60997
|
-
/* @__PURE__ */ jsx$1(Segmented, { label: "How to compare", help: "adv_method", left: "regression", right: "reweighting", active: vs.method === "reweighting" ? "right" : "left", onPick: (s2) => editConfig({ ...config2, method: some(s2 === "right" ? variant("propensity_score_weighting", { weighting_scheme: none$1 }) : variant("linear_regression", null)) }) }),
|
|
60998
|
-
/* @__PURE__ */ jsx$1(Segmented, { label: "Answer for", help: "adv_estimand", left: "all", right: "only treated", active: vs.target === "treated" ? "right" : "left", onPick: (s2) => editConfig({ ...config2, estimand: some(variant(s2 === "right" ? "att" : "ate", null)) }), last: true })
|
|
61052
|
+
/* @__PURE__ */ jsx$1(Segmented, { label: "How to compare", help: "adv_method", left: "regression", right: "reweighting", active: vs.method === "reweighting" ? "right" : "left", readonly, onPick: (s2) => editConfig({ ...config2, method: some(s2 === "right" ? variant("propensity_score_weighting", { weighting_scheme: none$1 }) : variant("linear_regression", null)) }) }),
|
|
61053
|
+
/* @__PURE__ */ jsx$1(Segmented, { label: "Answer for", help: "adv_estimand", left: "all", right: "only treated", active: vs.target === "treated" ? "right" : "left", readonly, onPick: (s2) => editConfig({ ...config2, estimand: some(variant(s2 === "right" ? "att" : "ate", null)) }), last: true })
|
|
60999
61054
|
] })
|
|
61000
61055
|
] })
|
|
61001
61056
|
] }),
|
|
@@ -61069,7 +61124,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61069
61124
|
] })
|
|
61070
61125
|
] }),
|
|
61071
61126
|
tab === "answer" && a2 && /* @__PURE__ */ jsx$1(AnswerNumeric, { a: a2, verdict, higherBetter, badge, barList }),
|
|
61072
|
-
tab === "answer" && !a2 && ref && /* @__PURE__ */ jsx$1(RefusalZone, { refusal: ref, overlap: ov, naiveValue: (
|
|
61127
|
+
tab === "answer" && !a2 && ref && /* @__PURE__ */ jsx$1(RefusalZone, { refusal: ref, overlap: ov, naiveValue: (shownResult == null ? void 0 : shownResult.naive) ?? 0, outcome: vs.outcome }),
|
|
61073
61128
|
tab === "trust" && vr && /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
|
|
61074
61129
|
/* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", color: "fg.muted", mb: "3.5", children: /* @__PURE__ */ jsx$1(Help, { id: "trust_intro", children: "Before trusting the answer we tried to break it — colour shows pass / caution." }) }),
|
|
61075
61130
|
/* @__PURE__ */ jsx$1(Box, { layerStyle: "frame.flat", children: vr.checks.map((c2, i) => {
|
|
@@ -61171,7 +61226,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61171
61226
|
var _a3;
|
|
61172
61227
|
const id3 = getSomeorUndefined(r2.preset);
|
|
61173
61228
|
if (id3 === void 0) return null;
|
|
61174
|
-
const label = ((_a3 =
|
|
61229
|
+
const label = ((_a3 = configs.find((c2) => c2.id === id3)) == null ? void 0 : _a3.label) ?? id3;
|
|
61175
61230
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
61176
61231
|
" ",
|
|
61177
61232
|
/* @__PURE__ */ jsxs(Box, { as: "span", css: chip({ tone: "brand", size: "sm" }), children: [
|
|
@@ -61371,11 +61426,17 @@ function ValidatePanel({ vm, barList }) {
|
|
|
61371
61426
|
] }, i)) })
|
|
61372
61427
|
] });
|
|
61373
61428
|
}
|
|
61374
|
-
function FilterRail({ fields, population, onChange: onChange2, chip, button }) {
|
|
61429
|
+
function FilterRail({ fields, population, onChange: onChange2, chip, button, readonly }) {
|
|
61375
61430
|
const [open, setOpen] = useState(null);
|
|
61376
61431
|
const replaceAt = (i, p2) => onChange2(population.map((f2, j2) => j2 === i ? p2 : f2));
|
|
61377
61432
|
const removeAt = (i) => onChange2(population.filter((_2, j2) => j2 !== i));
|
|
61378
61433
|
const done = /* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "outline", size: "xs" }), onClick: () => setOpen(null), children: "Done" });
|
|
61434
|
+
if (readonly) {
|
|
61435
|
+
return /* @__PURE__ */ jsx$1(Box, { display: "flex", flexWrap: "wrap", gap: "1.5", alignItems: "center", children: population.length === 0 ? /* @__PURE__ */ jsxs(Box, { css: chip({ tone: "plain", numeric: true, shape: "rounded" }), children: [
|
|
61436
|
+
"all ",
|
|
61437
|
+
SUBJECT_MANY
|
|
61438
|
+
] }) : population.map((pred, i) => /* @__PURE__ */ jsx$1(Box, { css: chip({ tone: "brand", numeric: true, shape: "rounded" }), flexShrink: 0, children: /* @__PURE__ */ jsx$1(Box, { as: "span", whiteSpace: "nowrap", children: formatPredicate(pred) }) }, i)) });
|
|
61439
|
+
}
|
|
61379
61440
|
return /* @__PURE__ */ jsxs(Box, { display: "flex", flexWrap: "wrap", gap: "1.5", alignItems: "center", children: [
|
|
61380
61441
|
population.map((pred, i) => /* @__PURE__ */ jsx$1(
|
|
61381
61442
|
SliceEditPopover,
|
|
@@ -61436,7 +61497,13 @@ function ColumnMenu({ choices, onPick, children: children2 }) {
|
|
|
61436
61497
|
/* @__PURE__ */ jsx$1(Portal, { children: /* @__PURE__ */ jsx$1(Menu.Positioner, { children: /* @__PURE__ */ jsx$1(Menu.Content, { children: choices.map((c2) => /* @__PURE__ */ jsx$1(Menu.Item, { value: c2, onClick: () => onPick(c2), children: c2 }, c2)) }) }) })
|
|
61437
61498
|
] });
|
|
61438
61499
|
}
|
|
61439
|
-
function ColumnPick({ column: column2, kind, choices, onPick, badge, button }) {
|
|
61500
|
+
function ColumnPick({ column: column2, kind, choices, onPick, badge, button, readonly }) {
|
|
61501
|
+
if (readonly) {
|
|
61502
|
+
return /* @__PURE__ */ jsxs(Box, { css: button({ variant: "outline", size: "sm" }), gap: "1.5", cursor: "default", children: [
|
|
61503
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: column2 }),
|
|
61504
|
+
/* @__PURE__ */ jsx$1(Box, { as: "span", css: badge({ variant: "plain", size: "sm" }), textTransform: "none", letterSpacing: "normal", children: kind })
|
|
61505
|
+
] });
|
|
61506
|
+
}
|
|
61440
61507
|
return /* @__PURE__ */ jsx$1(ColumnMenu, { choices, onPick, children: /* @__PURE__ */ jsxs(Box, { as: "button", css: button({ variant: "outline", size: "sm" }), gap: "1.5", children: [
|
|
61441
61508
|
/* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: column2 }),
|
|
61442
61509
|
/* @__PURE__ */ jsx$1(Box, { as: "span", css: badge({ variant: "plain", size: "sm" }), textTransform: "none", letterSpacing: "normal", children: kind }),
|
|
@@ -61479,10 +61546,14 @@ function SegmentSelect({ options: options2, active, onPick, fill, size: size3 =
|
|
|
61479
61546
|
}
|
|
61480
61547
|
);
|
|
61481
61548
|
}
|
|
61482
|
-
function
|
|
61549
|
+
function SegmentStatic({ value, size: size3 = "xs" }) {
|
|
61550
|
+
const s2 = useSlotRecipe({ key: "segmentGroup" })({ size: size3 });
|
|
61551
|
+
return /* @__PURE__ */ jsx$1(Box, { css: s2.root, alignSelf: "flex-start", children: /* @__PURE__ */ jsx$1(Box, { css: s2.item, "data-state": "checked", children: /* @__PURE__ */ jsx$1(Box, { as: "span", css: s2.itemText, children: value }) }) });
|
|
61552
|
+
}
|
|
61553
|
+
function Segmented({ label, left, right, active, onPick, last: last2, help, readonly }) {
|
|
61483
61554
|
return /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", alignItems: "stretch", gap: "1.5", py: "2", borderBottomWidth: last2 ? "0" : "1px", borderColor: "border.subtle", children: [
|
|
61484
61555
|
/* @__PURE__ */ jsx$1(Text, { textStyle: "caption.eyebrow", textTransform: "none", letterSpacing: "normal", color: "fg.default", children: help ? /* @__PURE__ */ jsx$1(Help, { id: help, children: label }) : label }),
|
|
61485
|
-
/* @__PURE__ */ jsx$1(SegmentSelect, { options: [left, right], active: active === "left" ? 0 : 1, onPick: (i) => onPick(i === 0 ? "left" : "right"), fill: true, size: "xs" })
|
|
61556
|
+
readonly ? /* @__PURE__ */ jsx$1(SegmentStatic, { value: active === "left" ? left : right }) : /* @__PURE__ */ jsx$1(SegmentSelect, { options: [left, right], active: active === "left" ? 0 : 1, onPick: (i) => onPick(i === 0 ? "left" : "right"), fill: true, size: "xs" })
|
|
61486
61557
|
] });
|
|
61487
61558
|
}
|
|
61488
61559
|
implementUIComponent(Experiment.Component, EastChakraExperiment);
|