@gendive/chatllm 0.6.3 → 0.6.4
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/README.md +4 -5
- package/dist/react/index.d.mts +23 -13
- package/dist/react/index.d.ts +23 -13
- package/dist/react/index.js +140 -13
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +140 -13
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -931,12 +931,11 @@ const response = await fetch('http://localhost:11434/api/chat', {
|
|
|
931
931
|
|
|
932
932
|
```typescript
|
|
933
933
|
// DevDive Gateway API
|
|
934
|
-
const response = await fetch(
|
|
935
934
|
`https://prd-gtw.devdive.ai/model/text-generation/v1/${model}`,
|
|
936
935
|
{
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
936
|
+
const response = await fetch(
|
|
937
|
+
headers: {
|
|
938
|
+
'Content-Type': 'application/json',
|
|
940
939
|
'X-API-KEY': apiKey,
|
|
941
940
|
},
|
|
942
941
|
body: JSON.stringify({
|
|
@@ -948,5 +947,5 @@ const response = await fetch(
|
|
|
948
947
|
}
|
|
949
948
|
)
|
|
950
949
|
```
|
|
951
|
-
|
|
950
|
+
method: 'POST',
|
|
952
951
|
---
|
package/dist/react/index.d.mts
CHANGED
|
@@ -48,6 +48,26 @@ interface PersonalizationConfig {
|
|
|
48
48
|
language: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @description 마크다운 렌더러 컴포넌트
|
|
53
|
+
* 외부 의존성 없이 기본 마크다운 파싱 지원
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
interface ChoiceOption {
|
|
57
|
+
number: number;
|
|
58
|
+
text: string;
|
|
59
|
+
fullText: string;
|
|
60
|
+
}
|
|
61
|
+
interface MarkdownRendererProps {
|
|
62
|
+
/** 마크다운 텍스트 */
|
|
63
|
+
content: string;
|
|
64
|
+
/** 커스텀 클래스 */
|
|
65
|
+
className?: string;
|
|
66
|
+
/** 선택지 클릭 핸들러 */
|
|
67
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
68
|
+
}
|
|
69
|
+
declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
|
|
70
|
+
|
|
51
71
|
/**
|
|
52
72
|
* @description React UI 컴포넌트 타입 정의
|
|
53
73
|
*/
|
|
@@ -211,6 +231,8 @@ interface MessageListProps {
|
|
|
211
231
|
models?: ModelConfig[];
|
|
212
232
|
copiedId: string | null;
|
|
213
233
|
editingId: string | null;
|
|
234
|
+
/** 선택지 클릭 핸들러 */
|
|
235
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
214
236
|
}
|
|
215
237
|
interface MessageBubbleProps {
|
|
216
238
|
message: ChatMessage;
|
|
@@ -227,6 +249,7 @@ interface MessageBubbleProps {
|
|
|
227
249
|
activeAlternativeIndex?: number;
|
|
228
250
|
models?: ModelConfig[];
|
|
229
251
|
alternatives?: AlternativeResponse[];
|
|
252
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
230
253
|
}
|
|
231
254
|
interface InputProps {
|
|
232
255
|
value: string;
|
|
@@ -454,19 +477,6 @@ interface MemoryPanelProps {
|
|
|
454
477
|
}
|
|
455
478
|
declare const MemoryPanel: React$1.FC<MemoryPanelProps>;
|
|
456
479
|
|
|
457
|
-
/**
|
|
458
|
-
* @description 마크다운 렌더러 컴포넌트
|
|
459
|
-
* 외부 의존성 없이 기본 마크다운 파싱 지원
|
|
460
|
-
*/
|
|
461
|
-
|
|
462
|
-
interface MarkdownRendererProps {
|
|
463
|
-
/** 마크다운 텍스트 */
|
|
464
|
-
content: string;
|
|
465
|
-
/** 커스텀 클래스 */
|
|
466
|
-
className?: string;
|
|
467
|
-
}
|
|
468
|
-
declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
|
|
469
|
-
|
|
470
480
|
/**
|
|
471
481
|
* @description 링크 칩 컴포넌트
|
|
472
482
|
* 출처 링크를 칩 형태로 표시
|
package/dist/react/index.d.ts
CHANGED
|
@@ -48,6 +48,26 @@ interface PersonalizationConfig {
|
|
|
48
48
|
language: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @description 마크다운 렌더러 컴포넌트
|
|
53
|
+
* 외부 의존성 없이 기본 마크다운 파싱 지원
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
interface ChoiceOption {
|
|
57
|
+
number: number;
|
|
58
|
+
text: string;
|
|
59
|
+
fullText: string;
|
|
60
|
+
}
|
|
61
|
+
interface MarkdownRendererProps {
|
|
62
|
+
/** 마크다운 텍스트 */
|
|
63
|
+
content: string;
|
|
64
|
+
/** 커스텀 클래스 */
|
|
65
|
+
className?: string;
|
|
66
|
+
/** 선택지 클릭 핸들러 */
|
|
67
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
68
|
+
}
|
|
69
|
+
declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
|
|
70
|
+
|
|
51
71
|
/**
|
|
52
72
|
* @description React UI 컴포넌트 타입 정의
|
|
53
73
|
*/
|
|
@@ -211,6 +231,8 @@ interface MessageListProps {
|
|
|
211
231
|
models?: ModelConfig[];
|
|
212
232
|
copiedId: string | null;
|
|
213
233
|
editingId: string | null;
|
|
234
|
+
/** 선택지 클릭 핸들러 */
|
|
235
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
214
236
|
}
|
|
215
237
|
interface MessageBubbleProps {
|
|
216
238
|
message: ChatMessage;
|
|
@@ -227,6 +249,7 @@ interface MessageBubbleProps {
|
|
|
227
249
|
activeAlternativeIndex?: number;
|
|
228
250
|
models?: ModelConfig[];
|
|
229
251
|
alternatives?: AlternativeResponse[];
|
|
252
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
230
253
|
}
|
|
231
254
|
interface InputProps {
|
|
232
255
|
value: string;
|
|
@@ -454,19 +477,6 @@ interface MemoryPanelProps {
|
|
|
454
477
|
}
|
|
455
478
|
declare const MemoryPanel: React$1.FC<MemoryPanelProps>;
|
|
456
479
|
|
|
457
|
-
/**
|
|
458
|
-
* @description 마크다운 렌더러 컴포넌트
|
|
459
|
-
* 외부 의존성 없이 기본 마크다운 파싱 지원
|
|
460
|
-
*/
|
|
461
|
-
|
|
462
|
-
interface MarkdownRendererProps {
|
|
463
|
-
/** 마크다운 텍스트 */
|
|
464
|
-
content: string;
|
|
465
|
-
/** 커스텀 클래스 */
|
|
466
|
-
className?: string;
|
|
467
|
-
}
|
|
468
|
-
declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
|
|
469
|
-
|
|
470
480
|
/**
|
|
471
481
|
* @description 링크 칩 컴포넌트
|
|
472
482
|
* 출처 링크를 칩 형태로 표시
|
package/dist/react/index.js
CHANGED
|
@@ -1821,7 +1821,7 @@ var LinkChip = ({
|
|
|
1821
1821
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1822
1822
|
var IMAGE_REGEX = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
1823
1823
|
var LINK_REGEX = /(?<!!)\[([^\]]+)\]\(([^)]+)\)/g;
|
|
1824
|
-
var SOURCE_LINKS_REGEX = /(\*{0,2}출처:?\*{0,2}\s*)?((
|
|
1824
|
+
var SOURCE_LINKS_REGEX = /(\*{0,2}출처:?\*{0,2}\s*)?((?:(?<!!)\[`?[^\]]+`?\]\([^)]+\)\s*)+)/gi;
|
|
1825
1825
|
var CODE_BLOCK_REGEX = /```(\w*)\n?([\s\S]*?)```/g;
|
|
1826
1826
|
var INLINE_CODE_REGEX = /`([^`]+)`/g;
|
|
1827
1827
|
var BOLD_REGEX = /\*\*([^*]+)\*\*/g;
|
|
@@ -2066,6 +2066,96 @@ var CodeBlock = ({ language, code }) => {
|
|
|
2066
2066
|
}
|
|
2067
2067
|
);
|
|
2068
2068
|
};
|
|
2069
|
+
var ChoiceButtons = ({ choices, onChoiceClick }) => {
|
|
2070
|
+
const [hoveredIndex, setHoveredIndex] = import_react5.default.useState(null);
|
|
2071
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2072
|
+
"div",
|
|
2073
|
+
{
|
|
2074
|
+
className: "chatllm-choices",
|
|
2075
|
+
style: {
|
|
2076
|
+
display: "flex",
|
|
2077
|
+
flexDirection: "column",
|
|
2078
|
+
gap: "8px",
|
|
2079
|
+
margin: "16px 0",
|
|
2080
|
+
padding: "12px",
|
|
2081
|
+
backgroundColor: "var(--chatllm-bg-secondary, #f9fafb)",
|
|
2082
|
+
borderRadius: "12px",
|
|
2083
|
+
border: "1px solid var(--chatllm-border-light, #e5e7eb)"
|
|
2084
|
+
},
|
|
2085
|
+
children: [
|
|
2086
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2087
|
+
"div",
|
|
2088
|
+
{
|
|
2089
|
+
style: {
|
|
2090
|
+
fontSize: "12px",
|
|
2091
|
+
fontWeight: 600,
|
|
2092
|
+
color: "var(--chatllm-text-muted, #6b7280)",
|
|
2093
|
+
marginBottom: "4px",
|
|
2094
|
+
textTransform: "uppercase",
|
|
2095
|
+
letterSpacing: "0.5px"
|
|
2096
|
+
},
|
|
2097
|
+
children: "\uC120\uD0DD\uD558\uC138\uC694"
|
|
2098
|
+
}
|
|
2099
|
+
),
|
|
2100
|
+
choices.map((choice, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2101
|
+
"button",
|
|
2102
|
+
{
|
|
2103
|
+
onClick: () => onChoiceClick?.(choice),
|
|
2104
|
+
onMouseEnter: () => setHoveredIndex(index),
|
|
2105
|
+
onMouseLeave: () => setHoveredIndex(null),
|
|
2106
|
+
style: {
|
|
2107
|
+
display: "flex",
|
|
2108
|
+
alignItems: "center",
|
|
2109
|
+
gap: "12px",
|
|
2110
|
+
padding: "12px 16px",
|
|
2111
|
+
backgroundColor: hoveredIndex === index ? "var(--chatllm-primary-light, #dbeafe)" : "var(--chatllm-bg, #ffffff)",
|
|
2112
|
+
border: "1px solid var(--chatllm-border, #e5e7eb)",
|
|
2113
|
+
borderRadius: "8px",
|
|
2114
|
+
cursor: "pointer",
|
|
2115
|
+
textAlign: "left",
|
|
2116
|
+
transition: "all 0.2s ease",
|
|
2117
|
+
transform: hoveredIndex === index ? "translateX(4px)" : "translateX(0)"
|
|
2118
|
+
},
|
|
2119
|
+
children: [
|
|
2120
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2121
|
+
"span",
|
|
2122
|
+
{
|
|
2123
|
+
style: {
|
|
2124
|
+
display: "flex",
|
|
2125
|
+
alignItems: "center",
|
|
2126
|
+
justifyContent: "center",
|
|
2127
|
+
width: "28px",
|
|
2128
|
+
height: "28px",
|
|
2129
|
+
borderRadius: "50%",
|
|
2130
|
+
backgroundColor: hoveredIndex === index ? "var(--chatllm-primary, #3b82f6)" : "var(--chatllm-bg-tertiary, #f3f4f6)",
|
|
2131
|
+
color: hoveredIndex === index ? "#ffffff" : "var(--chatllm-text, #374151)",
|
|
2132
|
+
fontSize: "14px",
|
|
2133
|
+
fontWeight: 600,
|
|
2134
|
+
flexShrink: 0,
|
|
2135
|
+
transition: "all 0.2s ease"
|
|
2136
|
+
},
|
|
2137
|
+
children: choice.number
|
|
2138
|
+
}
|
|
2139
|
+
),
|
|
2140
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2141
|
+
"span",
|
|
2142
|
+
{
|
|
2143
|
+
style: {
|
|
2144
|
+
fontSize: "14px",
|
|
2145
|
+
color: "var(--chatllm-text, #374151)",
|
|
2146
|
+
lineHeight: "1.5"
|
|
2147
|
+
},
|
|
2148
|
+
children: choice.text
|
|
2149
|
+
}
|
|
2150
|
+
)
|
|
2151
|
+
]
|
|
2152
|
+
},
|
|
2153
|
+
choice.number
|
|
2154
|
+
))
|
|
2155
|
+
]
|
|
2156
|
+
}
|
|
2157
|
+
);
|
|
2158
|
+
};
|
|
2069
2159
|
var SourceLinksSection = ({ links, label }) => {
|
|
2070
2160
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2071
2161
|
"div",
|
|
@@ -2099,7 +2189,7 @@ var SourceLinksSection = ({ links, label }) => {
|
|
|
2099
2189
|
}
|
|
2100
2190
|
);
|
|
2101
2191
|
};
|
|
2102
|
-
var MarkdownRenderer = ({ content, className }) => {
|
|
2192
|
+
var MarkdownRenderer = ({ content, className, onChoiceClick }) => {
|
|
2103
2193
|
const rendered = (0, import_react5.useMemo)(() => {
|
|
2104
2194
|
const elements = [];
|
|
2105
2195
|
let processedContent = content;
|
|
@@ -2121,6 +2211,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2121
2211
|
let currentList = null;
|
|
2122
2212
|
let blockquoteLines = [];
|
|
2123
2213
|
let tableLines = [];
|
|
2214
|
+
let choiceItems = [];
|
|
2124
2215
|
const flushTable = () => {
|
|
2125
2216
|
if (tableLines.length >= 2) {
|
|
2126
2217
|
const headerLine = tableLines[0];
|
|
@@ -2149,6 +2240,24 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2149
2240
|
}
|
|
2150
2241
|
tableLines = [];
|
|
2151
2242
|
};
|
|
2243
|
+
const flushChoices = () => {
|
|
2244
|
+
if (choiceItems.length >= 2 && onChoiceClick) {
|
|
2245
|
+
elements.push(
|
|
2246
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2247
|
+
ChoiceButtons,
|
|
2248
|
+
{
|
|
2249
|
+
choices: choiceItems,
|
|
2250
|
+
onChoiceClick
|
|
2251
|
+
},
|
|
2252
|
+
`choices-${elements.length}`
|
|
2253
|
+
)
|
|
2254
|
+
);
|
|
2255
|
+
choiceItems = [];
|
|
2256
|
+
return true;
|
|
2257
|
+
}
|
|
2258
|
+
choiceItems = [];
|
|
2259
|
+
return false;
|
|
2260
|
+
};
|
|
2152
2261
|
const flushList = () => {
|
|
2153
2262
|
if (currentList) {
|
|
2154
2263
|
if (currentList.type === "ul") {
|
|
@@ -2156,9 +2265,11 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2156
2265
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { style: { margin: "8px 0", paddingLeft: "24px" }, children: currentList.items }, `ul-${elements.length}`)
|
|
2157
2266
|
);
|
|
2158
2267
|
} else {
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2268
|
+
if (!flushChoices()) {
|
|
2269
|
+
elements.push(
|
|
2270
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ol", { style: { margin: "8px 0", paddingLeft: "24px" }, children: currentList.items }, `ol-${elements.length}`)
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2162
2273
|
}
|
|
2163
2274
|
currentList = null;
|
|
2164
2275
|
}
|
|
@@ -2287,15 +2398,24 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2287
2398
|
);
|
|
2288
2399
|
return;
|
|
2289
2400
|
}
|
|
2290
|
-
const olMatch = line.match(/^(\d+)
|
|
2401
|
+
const olMatch = line.match(/^(\d+)[.)]\s+(.+)$/);
|
|
2291
2402
|
if (olMatch) {
|
|
2292
2403
|
flushBlockquote();
|
|
2293
2404
|
if (!currentList || currentList.type !== "ol") {
|
|
2294
2405
|
flushList();
|
|
2295
2406
|
currentList = { type: "ol", items: [] };
|
|
2296
2407
|
}
|
|
2408
|
+
const itemNumber = parseInt(olMatch[1]);
|
|
2409
|
+
const itemText = olMatch[2];
|
|
2410
|
+
if (itemText.length <= 100) {
|
|
2411
|
+
choiceItems.push({
|
|
2412
|
+
number: itemNumber,
|
|
2413
|
+
text: itemText,
|
|
2414
|
+
fullText: line
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2297
2417
|
currentList.items.push(
|
|
2298
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { style: { margin: "4px 0" }, children: parseInlineElements(
|
|
2418
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { style: { margin: "4px 0" }, children: parseInlineElements(itemText, `li-${lineIndex}`) }, `li-${lineIndex}`)
|
|
2299
2419
|
);
|
|
2300
2420
|
return;
|
|
2301
2421
|
}
|
|
@@ -2312,7 +2432,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2312
2432
|
flushBlockquote();
|
|
2313
2433
|
flushTable();
|
|
2314
2434
|
return elements;
|
|
2315
|
-
}, [content]);
|
|
2435
|
+
}, [content, onChoiceClick]);
|
|
2316
2436
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2317
2437
|
"div",
|
|
2318
2438
|
{
|
|
@@ -2343,7 +2463,8 @@ var MessageBubble = ({
|
|
|
2343
2463
|
alternatives,
|
|
2344
2464
|
activeAlternativeIndex = 0,
|
|
2345
2465
|
onAlternativeChange,
|
|
2346
|
-
nextAssistantMessage
|
|
2466
|
+
nextAssistantMessage,
|
|
2467
|
+
onChoiceClick
|
|
2347
2468
|
}) => {
|
|
2348
2469
|
const [showActions, setShowActions] = (0, import_react6.useState)(false);
|
|
2349
2470
|
const [showModelMenu, setShowModelMenu] = (0, import_react6.useState)(false);
|
|
@@ -2447,7 +2568,7 @@ var MessageBubble = ({
|
|
|
2447
2568
|
children: [
|
|
2448
2569
|
isAssistant ? (
|
|
2449
2570
|
// AI 메시지는 마크다운 렌더링
|
|
2450
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: displayContent })
|
|
2571
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: displayContent, onChoiceClick })
|
|
2451
2572
|
) : (
|
|
2452
2573
|
// 사용자 메시지는 일반 텍스트
|
|
2453
2574
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
@@ -2736,7 +2857,8 @@ var MessageList = ({
|
|
|
2736
2857
|
activeAlternatives = {},
|
|
2737
2858
|
models,
|
|
2738
2859
|
copiedId,
|
|
2739
|
-
editingId
|
|
2860
|
+
editingId,
|
|
2861
|
+
onChoiceClick
|
|
2740
2862
|
}) => {
|
|
2741
2863
|
const messagesEndRef = (0, import_react7.useRef)(null);
|
|
2742
2864
|
const containerRef = (0, import_react7.useRef)(null);
|
|
@@ -2808,7 +2930,8 @@ var MessageList = ({
|
|
|
2808
2930
|
onAskOtherModel: message.role === "user" && assistantForAlts && onAskOtherModel ? (targetModel) => onAskOtherModel(message.id, assistantForAlts.id, targetModel) : void 0,
|
|
2809
2931
|
onAlternativeChange: message.role === "user" && assistantForAlts && onSetActiveAlternative ? (idx) => onSetActiveAlternative(assistantForAlts.id, idx) : message.role === "assistant" && onSetActiveAlternative ? (idx) => onSetActiveAlternative(message.id, idx) : void 0,
|
|
2810
2932
|
models,
|
|
2811
|
-
alternatives: message.role === "assistant" ? message.alternatives : assistantForAlts?.alternatives
|
|
2933
|
+
alternatives: message.role === "assistant" ? message.alternatives : assistantForAlts?.alternatives,
|
|
2934
|
+
onChoiceClick: message.role === "assistant" ? onChoiceClick : void 0
|
|
2812
2935
|
},
|
|
2813
2936
|
message.id
|
|
2814
2937
|
);
|
|
@@ -4161,6 +4284,9 @@ var ChatUI = ({
|
|
|
4161
4284
|
const handleSubmit = () => {
|
|
4162
4285
|
sendMessage();
|
|
4163
4286
|
};
|
|
4287
|
+
const handleChoiceClick = (choice) => {
|
|
4288
|
+
setInput(choice.text);
|
|
4289
|
+
};
|
|
4164
4290
|
const [memoryPanelOpen, setMemoryPanelOpen] = (0, import_react10.useState)(false);
|
|
4165
4291
|
const memoryItems = import_react10.default.useMemo(() => {
|
|
4166
4292
|
const items = [];
|
|
@@ -4272,7 +4398,8 @@ var ChatUI = ({
|
|
|
4272
4398
|
activeAlternatives,
|
|
4273
4399
|
models: hookModels,
|
|
4274
4400
|
copiedId: copiedMessageId,
|
|
4275
|
-
editingId: editingMessageId
|
|
4401
|
+
editingId: editingMessageId,
|
|
4402
|
+
onChoiceClick: handleChoiceClick
|
|
4276
4403
|
}
|
|
4277
4404
|
),
|
|
4278
4405
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|