693 lines
23 KiB
JavaScript
693 lines
23 KiB
JavaScript
/*
|
|
* Extracted from browser-delivered Turbopack chunk: 042913757dfeb33b.7750222294.js
|
|
* Module id: 848024
|
|
* For reading/searching only; this factory depends on the original Turbopack runtime.
|
|
*/
|
|
|
|
const moduleFactory = (e) => {
|
|
"use strict";
|
|
var t = e.i(462214),
|
|
r = e.i(358379),
|
|
i = e.i(529833),
|
|
n = e.i(906328),
|
|
a = e.i(41671),
|
|
s = e.i(384916),
|
|
l = e.i(722573),
|
|
o = e.i(440398),
|
|
u = e.i(791997),
|
|
c = e.i(41114),
|
|
d = e.i(234954);
|
|
let f = {
|
|
"4:5": [10, 12],
|
|
"1:1": [12, 12],
|
|
"5:4": [12, 10],
|
|
"4:3": [12, 9],
|
|
"3:2": [12, 8],
|
|
"16:9": [16, 9],
|
|
"21:9": [16, 7],
|
|
"9:21": [7, 16],
|
|
"9:16": [9, 16],
|
|
"2:3": [9, 12],
|
|
"3:4": [9, 12],
|
|
auto: [12, 12],
|
|
};
|
|
function p(e, t) {
|
|
return e?.settings
|
|
? Array.isArray(e.settings)
|
|
? e.settings
|
|
: (e.settings[t] ?? e.settings.text2video ?? [])
|
|
: [];
|
|
}
|
|
function m(e) {
|
|
return e
|
|
? e.map((e) =>
|
|
"object" == typeof e && null !== e
|
|
? { value: e.value, displayName: e.displayName }
|
|
: { value: e, displayName: String(e) },
|
|
)
|
|
: [];
|
|
}
|
|
function g(e) {
|
|
if (!e) return;
|
|
if (void 0 !== e.default) return e.default;
|
|
let t = m(e.enum);
|
|
return t[0]?.value;
|
|
}
|
|
function h(e, t) {
|
|
return t?.originalField ?? e;
|
|
}
|
|
function y(e, t, r, i) {
|
|
let n = {},
|
|
a = e.settings ?? {};
|
|
return (
|
|
r.forEach((e) => {
|
|
let r = t[e];
|
|
if (!r) return;
|
|
let s = a[h(e, r)];
|
|
if ("slider" === r.component) {
|
|
let t = Number(s),
|
|
a = i?.[e],
|
|
l = a?.min ?? r.min ?? 0,
|
|
o = a?.max ?? r.max ?? 100;
|
|
void 0 === s || isNaN(t)
|
|
? (n[e] = a?.default ?? r.default ?? l)
|
|
: (n[e] = Math.min(Math.max(t, l), o));
|
|
} else if ("switch" === r.component)
|
|
void 0 !== s ? (n[e] = s) : (n[e] = r.default ?? 0);
|
|
else {
|
|
let t = m(r.enum).map((e) => e.value);
|
|
void 0 !== s && t.includes(s) ? (n[e] = s) : (n[e] = g(r));
|
|
}
|
|
}),
|
|
n
|
|
);
|
|
}
|
|
function v({ ratio: e, isSelected: r }) {
|
|
let i = f[e] ?? [12, 9];
|
|
return (0, t.jsx)("span", {
|
|
className: "flex size-[17px] items-center justify-center",
|
|
children: (0, t.jsx)("span", {
|
|
className: (0, c.cn)(
|
|
"flex-none rounded-[2px] border-[1.5px] border-current",
|
|
),
|
|
style: { width: `${i[0]}px`, height: `${i[1]}px` },
|
|
}),
|
|
});
|
|
}
|
|
function b({
|
|
label: e,
|
|
tips: r,
|
|
options: i,
|
|
value: n,
|
|
onChange: s,
|
|
isRatio: o = !1,
|
|
disabledValues: u,
|
|
disabledMessage: d,
|
|
fullyLocked: f = !1,
|
|
fullyLockedHint: p,
|
|
}) {
|
|
return (0, t.jsxs)("div", {
|
|
className: "flex flex-col gap-2",
|
|
children: [
|
|
(0, t.jsxs)("div", {
|
|
className:
|
|
"text-fg-muted flex items-center gap-1.5 text-sm font-medium",
|
|
children: [
|
|
(0, t.jsx)("span", { children: e }),
|
|
r &&
|
|
(0, t.jsx)(l.Tooltip, {
|
|
label: r,
|
|
withArrow: !0,
|
|
position: "top",
|
|
multiline: !0,
|
|
maw: 200,
|
|
children: (0, t.jsx)("div", {
|
|
className: "cursor-help",
|
|
children: (0, t.jsx)(a.Icons.tablerHelp, {
|
|
className: "text-fg-muted size-3",
|
|
}),
|
|
}),
|
|
}),
|
|
],
|
|
}),
|
|
o
|
|
? (0, t.jsx)("div", {
|
|
className: (0, c.cn)(
|
|
"gap-2",
|
|
i.length > 5 ? "grid grid-cols-5" : "flex",
|
|
),
|
|
children: i.map((e) => {
|
|
let r = e.value === n,
|
|
i = u?.has(e.value) ?? !1,
|
|
a = f ? !r : i,
|
|
m = (0, t.jsxs)(
|
|
"button",
|
|
{
|
|
type: "button",
|
|
onClick: f || a ? void 0 : () => s(e.value),
|
|
className: (0, c.cn)(
|
|
"border-hair flex flex-1 flex-col items-center justify-center gap-1 rounded-lg border-solid px-1 py-3 transition-colors duration-200",
|
|
a
|
|
? "border-border-default text-fg-muted cursor-not-allowed opacity-40"
|
|
: r
|
|
? "border-border-strong bg-white-alpha-10 text-fg-default"
|
|
: "border-border-default text-fg-muted bg-transparent",
|
|
),
|
|
children: [
|
|
(0, t.jsx)(v, {
|
|
ratio: String(e.value),
|
|
isSelected: r && !a,
|
|
}),
|
|
(0, t.jsx)("span", {
|
|
className: "text-xs",
|
|
children: e.displayName,
|
|
}),
|
|
],
|
|
},
|
|
String(e.value),
|
|
);
|
|
return a && (d || f)
|
|
? (0, t.jsx)(
|
|
l.Tooltip,
|
|
{
|
|
label: f
|
|
? o
|
|
? "全景模式下画幅比例已固定"
|
|
: (p ?? "当前设置项已锁定")
|
|
: (d ?? ""),
|
|
withArrow: !0,
|
|
position: "top",
|
|
multiline: !0,
|
|
maw: 200,
|
|
children: (0, t.jsx)("div", {
|
|
className: "flex flex-1",
|
|
children: m,
|
|
}),
|
|
},
|
|
String(e.value),
|
|
)
|
|
: m;
|
|
}),
|
|
})
|
|
: (0, t.jsx)("div", {
|
|
className: "flex gap-2",
|
|
children: i.map((e) => {
|
|
let r = e.value === n,
|
|
i = u?.has(e.value) ?? !1,
|
|
a = f ? !r : i,
|
|
o = (0, t.jsx)(
|
|
"button",
|
|
{
|
|
type: "button",
|
|
onClick: f || a ? void 0 : () => s(e.value),
|
|
className: (0, c.cn)(
|
|
"border-border-default border-hair flex h-8 flex-1 items-center justify-center rounded-lg border-solid text-[13px] transition-colors duration-200",
|
|
a
|
|
? "cursor-not-allowed opacity-40"
|
|
: r
|
|
? "bg-white-alpha-10 text-fg-default"
|
|
: "text-fg-muted bg-transparent",
|
|
),
|
|
children: e.displayName,
|
|
},
|
|
String(e.value),
|
|
);
|
|
return a && (d || f)
|
|
? (0, t.jsx)(
|
|
l.Tooltip,
|
|
{
|
|
label: f ? (p ?? "当前设置项已锁定") : (d ?? ""),
|
|
withArrow: !0,
|
|
position: "top",
|
|
multiline: !0,
|
|
maw: 200,
|
|
children: (0, t.jsx)("div", {
|
|
className: "flex flex-1",
|
|
children: o,
|
|
}),
|
|
},
|
|
String(e.value),
|
|
)
|
|
: o;
|
|
}),
|
|
}),
|
|
],
|
|
});
|
|
}
|
|
let w = {
|
|
track: {
|
|
backgroundColor:
|
|
"color-mix(in srgb, var(--color-fg-muted) 30%, transparent)",
|
|
transition: "none",
|
|
},
|
|
bar: { transition: "none" },
|
|
thumb: {
|
|
backgroundColor: "white",
|
|
borderWidth: "0.5px",
|
|
borderColor: "#262626",
|
|
boxShadow: "none",
|
|
transition: "none",
|
|
},
|
|
};
|
|
function x({
|
|
label: e,
|
|
tips: i,
|
|
value: s,
|
|
min: o,
|
|
max: u,
|
|
step: c,
|
|
unit: d,
|
|
onChange: f,
|
|
}) {
|
|
let [p, m] = (0, r.useState)(s);
|
|
return (
|
|
(0, r.useEffect)(() => {
|
|
m(s);
|
|
}, [s]),
|
|
(0, t.jsxs)("div", {
|
|
className: "flex flex-col gap-2",
|
|
children: [
|
|
(0, t.jsxs)("div", {
|
|
className:
|
|
"text-fg-muted flex items-center gap-1.5 text-sm font-medium",
|
|
children: [
|
|
(0, t.jsx)("span", { children: e }),
|
|
i &&
|
|
(0, t.jsx)(l.Tooltip, {
|
|
label: i,
|
|
withArrow: !0,
|
|
position: "top",
|
|
multiline: !0,
|
|
maw: 200,
|
|
children: (0, t.jsx)("div", {
|
|
className: "cursor-help",
|
|
children: (0, t.jsx)(a.Icons.tablerHelp, {
|
|
className: "text-fg-muted size-3",
|
|
}),
|
|
}),
|
|
}),
|
|
],
|
|
}),
|
|
(0, t.jsxs)("div", {
|
|
className: "flex items-center gap-2",
|
|
children: [
|
|
(0, t.jsx)(n.Slider, {
|
|
value: p,
|
|
onChange: m,
|
|
onChangeEnd: (e) => f(e),
|
|
min: o,
|
|
max: u,
|
|
step: c,
|
|
size: "xs",
|
|
thumbSize: 12,
|
|
color: "blue",
|
|
className: "flex-1",
|
|
styles: w,
|
|
}),
|
|
(0, t.jsxs)("span", {
|
|
className: "text-fg-muted w-8 shrink-0 text-right text-xs",
|
|
children: [p, d],
|
|
}),
|
|
],
|
|
}),
|
|
],
|
|
})
|
|
);
|
|
}
|
|
function A({ label: e, tips: r, value: i, onChange: n }) {
|
|
return (0, t.jsxs)("div", {
|
|
className: "flex items-center justify-between py-1",
|
|
children: [
|
|
(0, t.jsxs)("div", {
|
|
className:
|
|
"text-fg-muted flex items-center gap-1.5 text-sm font-medium",
|
|
children: [
|
|
(0, t.jsx)("span", { children: e }),
|
|
r &&
|
|
(0, t.jsx)(l.Tooltip, {
|
|
label: r,
|
|
withArrow: !0,
|
|
position: "top",
|
|
multiline: !0,
|
|
maw: 200,
|
|
children: (0, t.jsx)("div", {
|
|
className: "cursor-help",
|
|
children: (0, t.jsx)(a.Icons.tablerHelp, {
|
|
className: "text-fg-muted size-3",
|
|
}),
|
|
}),
|
|
}),
|
|
],
|
|
}),
|
|
(0, t.jsx)(s.Switch, {
|
|
checked: i,
|
|
onChange: (e) => n(e.currentTarget.checked),
|
|
}),
|
|
],
|
|
});
|
|
}
|
|
function S({
|
|
params: e,
|
|
modelSchema: n,
|
|
onParamsChange: s,
|
|
disabled: f,
|
|
disabledReason: g,
|
|
lockRatioOnly: w = !1,
|
|
}) {
|
|
let S,
|
|
j = (0, u.useCanvasThemeStore)((e) => e.theme),
|
|
[C, E] = (0, r.useState)(!1),
|
|
T = (0, r.useRef)(null),
|
|
N = (0, r.useRef)(null),
|
|
M = (0, d.usePopoverManager)(),
|
|
O = (0, r.useId)(),
|
|
P = (0, r.useMemo)(() => n?.properties ?? {}, [n?.properties]),
|
|
L = (0, r.useMemo)(() => n?.config, [n?.config]),
|
|
k = e.modeType ?? "text2video",
|
|
R = (0, r.useMemo)(() => p(L, k), [L, k]),
|
|
[I, U] = (0, r.useState)(() => y(e, P, R)),
|
|
D = (0, r.useMemo)(
|
|
() => (0, o.sanitizeSettingsRules)(n?.settingsRules),
|
|
[n?.settingsRules],
|
|
),
|
|
V = (0, r.useMemo)(
|
|
() => ({
|
|
videoList: e.videoList?.length ?? 0,
|
|
imageList: e.imageList?.length ?? 0,
|
|
audioList: e.audioList?.length ?? 0,
|
|
}),
|
|
[e.videoList?.length, e.imageList?.length, e.audioList?.length],
|
|
),
|
|
{
|
|
disabledMap: $,
|
|
fallbacks: W,
|
|
messages: z,
|
|
overrides: H,
|
|
} = (0, r.useMemo)(
|
|
() => (0, o.evaluateSettingsRules)(D, I, k, V),
|
|
[D, I, k, V],
|
|
),
|
|
_ = (0, r.useMemo)(() => {
|
|
let e = { ...W };
|
|
for (let t of R) {
|
|
let r = $[t];
|
|
if (!r?.has(I[t]) || void 0 !== e[t]) continue;
|
|
let i = m(P[t]?.enum).find((e) => !r.has(e.value));
|
|
i && (e[t] = i.value);
|
|
}
|
|
return e;
|
|
}, [W, $, I, R, P]),
|
|
F = (0, r.useRef)(e);
|
|
F.current = e;
|
|
let K = (0, r.useRef)(P);
|
|
(K.current = P),
|
|
(0, r.useEffect)(() => {
|
|
let e = K.current,
|
|
t = y(F.current, e, R);
|
|
U(t);
|
|
let r = F.current.settings ?? {},
|
|
i = {};
|
|
R.forEach((n) => {
|
|
let a = e[n];
|
|
if (!a) return;
|
|
let s = h(n, a);
|
|
t[n] !== r[s] && (i[s] = t[n]);
|
|
}),
|
|
Object.keys(i).length > 0 && s({ settings: { ...r, ...i } });
|
|
}, [k, R, e.settings, s]),
|
|
(0, r.useEffect)(() => {
|
|
if (M)
|
|
return M.register({
|
|
id: O,
|
|
targetRef: T,
|
|
dropdownRef: N,
|
|
close: () => E(!1),
|
|
});
|
|
}, [M, O]),
|
|
(0, r.useEffect)(() => {
|
|
f && E(!1);
|
|
}, [f]);
|
|
let q = (0, r.useMemo)(() => JSON.stringify(_), [_]);
|
|
(0, r.useEffect)(() => {
|
|
if (0 === Object.keys(_).length) return;
|
|
let e = K.current,
|
|
t = F.current.settings ?? {},
|
|
r = {};
|
|
for (let [t, i] of Object.entries(_)) {
|
|
let n = e[t];
|
|
r[h(t, n)] = i;
|
|
}
|
|
Object.keys(r).length > 0 &&
|
|
(U((e) => {
|
|
let t = { ...e };
|
|
for (let [e, r] of Object.entries(_)) t[e] = r;
|
|
return t;
|
|
}),
|
|
s({ settings: { ...t, ...r } }));
|
|
}, [q, s]);
|
|
let B = (0, r.useRef)(I);
|
|
B.current = I;
|
|
let J = (0, r.useMemo)(() => JSON.stringify(H), [H]);
|
|
(0, r.useEffect)(() => {
|
|
if (0 === Object.keys(H).length) return;
|
|
let e = K.current,
|
|
t = F.current.settings ?? {},
|
|
r = B.current,
|
|
i = {},
|
|
n = {};
|
|
for (let [t, a] of Object.entries(H)) {
|
|
let s = e[t];
|
|
if (!s || "slider" !== s.component) continue;
|
|
let l = a.min ?? s.min ?? 0,
|
|
o = a.max ?? s.max ?? 100,
|
|
u = Number(r[t]);
|
|
if (isNaN(u)) continue;
|
|
let c = Math.min(Math.max(u, l), o);
|
|
if (c !== u) {
|
|
let e = h(t, s);
|
|
(i[t] = c), (n[e] = c);
|
|
}
|
|
}
|
|
Object.keys(i).length > 0 &&
|
|
(U((e) => ({ ...e, ...i })), s({ settings: { ...t, ...n } }));
|
|
}, [J, s]);
|
|
let Y = (0, r.useCallback)(
|
|
(e, t) => {
|
|
let r = K.current[e],
|
|
i = h(e, r);
|
|
U((r) => ({ ...r, [e]: t })),
|
|
s({ settings: { ...(F.current.settings ?? {}), [i]: t } });
|
|
},
|
|
[s],
|
|
),
|
|
G = (0, r.useMemo)(() => {
|
|
let e = (e) =>
|
|
null == e
|
|
? ""
|
|
: "object" == typeof e
|
|
? JSON.stringify(e)
|
|
: String(e),
|
|
t = [],
|
|
r = R.find((e) => e.startsWith("ratio")),
|
|
i = !1;
|
|
if (r) {
|
|
let n = I[r],
|
|
a = P[r],
|
|
s = m(a?.enum).find((e) => e.value === n),
|
|
l = s?.displayName ?? e(n);
|
|
(i = "auto" === e(n).toLowerCase()),
|
|
l && t.push({ type: "ratio", value: l, rawValue: n });
|
|
}
|
|
let n = R.find((e) => "quality" === e);
|
|
if (n) {
|
|
let r = I[n],
|
|
i = P[n],
|
|
a = m(i?.enum).find((e) => e.value === r),
|
|
s = a?.displayName ?? e(r);
|
|
s && t.push({ type: "quality", value: s });
|
|
}
|
|
let a = R.find((e) => e.startsWith("resolution"));
|
|
if (a) {
|
|
let r = I[a],
|
|
n = P[a],
|
|
s = m(n?.enum).find((e) => e.value === r),
|
|
l = s?.displayName ?? e(r),
|
|
o = "auto" === e(r).toLowerCase();
|
|
!(i && o) && l && t.push({ type: "resolution", value: l });
|
|
}
|
|
let s = R.find((e) => e.startsWith("duration"));
|
|
if (s) {
|
|
let r = I[s];
|
|
void 0 !== r && t.push({ type: "duration", value: `${e(r)}s` });
|
|
}
|
|
let l = R.find((e) => "enableSound" === e);
|
|
return l && "on" === I[l] && t.push({ type: "sound", value: "" }), t;
|
|
}, [R, I, P]),
|
|
Q = (0, r.useMemo)(() => {
|
|
let e = G.filter((e) => "sound" !== e.type)
|
|
.map((e) => e.value)
|
|
.join(" · ");
|
|
return G.find((e) => "sound" === e.type) ? `${e} \xb7` : e;
|
|
}, [G]);
|
|
return 0 === R.length
|
|
? null
|
|
: (0, t.jsxs)(i.Popover, {
|
|
opened: !f && C,
|
|
onChange: f ? () => void 0 : E,
|
|
position: "bottom-start",
|
|
offset: 0,
|
|
shadow: "md",
|
|
radius: "md",
|
|
withinPortal: !0,
|
|
closeOnClickOutside: !1,
|
|
children: [
|
|
(0, t.jsx)(i.Popover.Target, {
|
|
children: (0, t.jsx)(l.Tooltip, {
|
|
label: f
|
|
? (g ?? "全景模式下已锁定比例与分辨率")
|
|
: w
|
|
? (g ?? "全景模式下已锁定画幅比例,可选择分辨率")
|
|
: "",
|
|
disabled: !f && !w,
|
|
position: "top",
|
|
openDelay: 300,
|
|
children: (0, t.jsxs)("button", {
|
|
type: "button",
|
|
ref: T,
|
|
disabled: f,
|
|
onClick: () => {
|
|
f || (M?.closeAll(O), E((e) => !e));
|
|
},
|
|
className: (0, c.cn)(
|
|
"flex h-8 shrink items-center justify-between gap-1 rounded-lg bg-transparent px-2 py-1 transition-colors",
|
|
f
|
|
? "cursor-not-allowed opacity-50"
|
|
: "hover:bg-btn-ghost-hover cursor-pointer",
|
|
!f && C && "bg-btn-ghost-hover",
|
|
),
|
|
children: [
|
|
(0, t.jsxs)("div", {
|
|
className:
|
|
"flex min-w-0 flex-1 items-center gap-1 overflow-hidden",
|
|
children: [
|
|
G.find((e) => "ratio" === e.type) &&
|
|
(0, t.jsx)(v, {
|
|
ratio:
|
|
null ==
|
|
(S = G.find(
|
|
(e) => "ratio" === e.type,
|
|
)?.rawValue)
|
|
? "16:9"
|
|
: "object" == typeof S
|
|
? JSON.stringify(S)
|
|
: String(S),
|
|
isSelected: !0,
|
|
}),
|
|
(0, t.jsx)("span", {
|
|
className: "text-fg-default truncate text-[13px]",
|
|
title: Q,
|
|
children: Q,
|
|
}),
|
|
G.find((e) => "sound" === e.type) &&
|
|
(0, t.jsx)(a.Icons.Audio, {
|
|
className: "text-fg-default size-3.5",
|
|
}),
|
|
],
|
|
}),
|
|
(0, t.jsx)(a.Icons.lucideChevronDown, {
|
|
className: (0, c.cn)(
|
|
"text-fg-muted size-3.5 shrink-0 transition-transform",
|
|
!f && C && "rotate-180",
|
|
),
|
|
}),
|
|
],
|
|
}),
|
|
}),
|
|
}),
|
|
(0, t.jsx)(i.Popover.Dropdown, {
|
|
ref: N,
|
|
className: `border-border-muted border-hair! p-0! bg-panel-background/95 rounded-2xl backdrop-blur-[32px] ${"light" === j ? "canvas-light" : ""}`,
|
|
style: { boxShadow: "var(--canvas-shadow-dropdown)" },
|
|
children: (0, t.jsx)("div", {
|
|
className: "flex w-[340px] flex-col gap-2 rounded-2xl p-3",
|
|
children: R.map((e) => {
|
|
let r = P[e];
|
|
if (!r || r.barOnly) return null;
|
|
if ("slider" === r.component) {
|
|
let i = e.startsWith("duration"),
|
|
n = H[e],
|
|
a = n?.min ?? r.min ?? 0,
|
|
s = n?.max ?? r.max ?? 100,
|
|
l = n?.step ?? r.step ?? 1,
|
|
o = Math.min(
|
|
Math.max(Number(I[e]) || r.default || 0, a),
|
|
s,
|
|
);
|
|
return (0, t.jsx)(
|
|
x,
|
|
{
|
|
label: r.displayName ?? e,
|
|
tips: n ? (z[e] ?? r.tips) : r.tips,
|
|
value: o,
|
|
min: a,
|
|
max: s,
|
|
step: l,
|
|
unit: i ? "s" : void 0,
|
|
onChange: (t) => Y(e, t),
|
|
},
|
|
e,
|
|
);
|
|
}
|
|
if ("switch" === r.component)
|
|
return (0, t.jsx)(
|
|
A,
|
|
{
|
|
label: r.displayName ?? e,
|
|
tips: r.tips,
|
|
value: !!I[e],
|
|
onChange: (t) => Y(e, +!!t),
|
|
},
|
|
e,
|
|
);
|
|
if ("singleButton" !== r.component) return null;
|
|
let i = m(r.enum);
|
|
if (0 === i.length) return null;
|
|
let n = e.startsWith("ratio"),
|
|
a = w && n;
|
|
return (0, t.jsx)(
|
|
b,
|
|
{
|
|
label: r.displayName ?? e,
|
|
tips: r.tips,
|
|
options: i,
|
|
value: I[e],
|
|
onChange: (t) => Y(e, t),
|
|
isRatio: n,
|
|
disabledValues: $[e],
|
|
disabledMessage: z[e],
|
|
fullyLocked: a,
|
|
},
|
|
e,
|
|
);
|
|
}),
|
|
}),
|
|
}),
|
|
],
|
|
});
|
|
}
|
|
e.s([
|
|
"default",
|
|
() => S,
|
|
"getDefaultValue",
|
|
() => g,
|
|
"getSettingKeys",
|
|
() => p,
|
|
"getStoreKey",
|
|
() => h,
|
|
"normalizeEnumOptions",
|
|
() => m,
|
|
]);
|
|
};
|
|
|
|
export default moduleFactory;
|