revert(802-1): 801-1 wip 옛 나무 위 고침 걷음 — 요구 664 수식 문서로 다시 짬
- 걷음: 43784a4c0 의 옛 수식 나무 위 고침(서버 · 화면 · css) = 그 앞 판으로 되돌림
- 남김: master_equation_sign.py · ui_template_equation_text.ts · ui_template_equation_edit.ts(다시 쓸 조각 · 지금 안 부름) · text 는 `입력글` 을 제 타입에
- 지움: test_801_1_equation_inline.py — 걷은 옛 나무 고침을 재는 시험
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -171,13 +171,15 @@
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 네 마디 — 결과명 = 기호 식 = 값 식 = 결과 값(801 — 박스 · 테두리 없는 조판 한 줄) */
|
||||
/* 네 칸 상자 — 결과명 = 이름 식 = 값 식 = 결과 값 */
|
||||
.ui-eq__box {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-4);
|
||||
padding: 2px var(--spacing-4);
|
||||
padding: var(--spacing-4) var(--spacing-8);
|
||||
border: 1px solid var(--color-border-strong);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface-raised);
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
@@ -204,43 +206,24 @@
|
||||
font-size: var(--text-caption);
|
||||
}
|
||||
|
||||
/* 바로 고침(801) — 보이는 식 그 자리(커서) · 값 숫자 그 자리 */
|
||||
/* 바로 고침 — 이름 식 칸을 누르면 그 자리에서 식 칸 */
|
||||
.ui-eq__name.is-edit {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.ui-eq__name.is-edit:hover,
|
||||
.ui-eq__name.is-edit:hover {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.ui-eq__name.is-open {
|
||||
background: var(--color-accent-soft);
|
||||
flex: 1 1 24rem;
|
||||
align-items: flex-start;
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.ui-eq__edit {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0 var(--spacing-4);
|
||||
min-width: 1ch;
|
||||
outline: none;
|
||||
caret-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.ui-eq__edit[data-bad="1"] {
|
||||
text-decoration: underline wavy var(--color-danger);
|
||||
}
|
||||
|
||||
.ui-eq__note {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: var(--text-caption);
|
||||
}
|
||||
|
||||
.ui-eq .is-value {
|
||||
cursor: pointer;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.ui-eq .is-value:hover,
|
||||
.ui-eq .is-value[data-editing] {
|
||||
background: var(--color-accent-soft);
|
||||
outline: none;
|
||||
.ui-eq__name.is-open > * {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 하위 로직 블록 — 접힘 */
|
||||
|
||||
@@ -6,14 +6,10 @@
|
||||
* 크기 = 글자 `--text-body` · 첨자 0.7 배 · 분수 안 글 같은 크기 · 변수 칩 높이는 글 줄
|
||||
* 상태 = 고르는 변수 `is-pick`(눌림 가능 · 머리 `data-size` 없음 — 글 속 부품) · 걸리지 않은 가지는 마우스 글로만
|
||||
* 쓰는 법 = `renderEq(tree, { onVar, onBlock })` → 인라인 요소 · 줄 · 풀이 · 블록 = `ui_template_equation_line.ts`
|
||||
* 801 = 박스 없는 조판 · 만약 = 탄 갈래만 · 반올림 감싸개 안 보임 · 로직 부름 = 기호 · 값 식 숫자 뒤 단위 ·
|
||||
* 바로 고침 표지(원자 `data-tok` · 감싸개 `data-pre` · `data-post` — 글 꼴 바꿈 = `ui_template_equation_text.ts` ·
|
||||
* `ui_template_equation_edit.ts`)
|
||||
* 대신하는 옛 변종 = `createCalcFormula` 의 `^…^` · `_…_` 글(분수 없음 · 그 부품은 그대로 둠)
|
||||
* ========================================================================== */
|
||||
|
||||
import "./ui_template_equation.css";
|
||||
import { HIDDEN, taken, textOf } from "./ui_template_equation_text";
|
||||
|
||||
/** 서버 나무 마디 — 꼴마다 쓰는 칸이 다름(변수 `위` · `아래` 는 첨자 글 · 분수 `위` · `아래` 는 마디) */
|
||||
export interface EqNode {
|
||||
@@ -29,8 +25,6 @@ export interface EqNode {
|
||||
단위?: string;
|
||||
갈래?: string;
|
||||
식?: string;
|
||||
/** 표 찾기 · 요소 · 로직 부름 키보드 글(801 · 서버 `_atoms`) */
|
||||
입력글?: string;
|
||||
칸?: string | null;
|
||||
표?: string;
|
||||
표이름?: string;
|
||||
@@ -148,8 +142,6 @@ export interface EqLine {
|
||||
원래?: unknown;
|
||||
지금?: unknown;
|
||||
뺌?: boolean;
|
||||
/** 801 — 식이 표 찾기 · 요소 · 로직 부름 한 마디뿐(「q = 0.7」 · 그 마디 기호 = 줄 기호) */
|
||||
한마디?: boolean;
|
||||
}
|
||||
|
||||
export interface EqHandlers {
|
||||
@@ -219,7 +211,7 @@ export function plainEq(node: EqNode | undefined): string {
|
||||
return sign + low + up;
|
||||
}
|
||||
case "블록":
|
||||
return node.기호 ? plainEq({ ...node, 꼴: "변수" }) : node.이름 || node.열쇠 || "";
|
||||
return node.이름 || node.열쇠 || "";
|
||||
case "연산":
|
||||
return `${plainEq(node.좌)} ${SHOW[node.기호 ?? ""] ?? node.기호} ${plainEq(node.우)}`;
|
||||
case "분수":
|
||||
@@ -230,13 +222,9 @@ export function plainEq(node: EqNode | undefined): string {
|
||||
return `${plainEq(node.안)}%`;
|
||||
case "음":
|
||||
return `−${plainEq(node.안)}`;
|
||||
case "조건": {
|
||||
const pick = taken(node);
|
||||
if (pick) return plainEq(pick);
|
||||
case "조건":
|
||||
return `만약(${plainEq(node.조건)}, ${plainEq(node.참)}, ${plainEq(node.거짓)})`;
|
||||
}
|
||||
case "함수":
|
||||
if (HIDDEN.has(node.이름 ?? "")) return plainEq(node.인자?.[0]);
|
||||
return `${node.이름}(${(node.인자 ?? []).map(plainEq).join(", ")})`;
|
||||
default:
|
||||
return "";
|
||||
@@ -246,7 +234,6 @@ export function plainEq(node: EqNode | undefined): string {
|
||||
/** 변수 한 개 — 눌리면 `onVar` */
|
||||
function variable(node: EqNode, h: EqHandlers): HTMLElement {
|
||||
const box = span("ui-eq__var", symbolOf(node));
|
||||
box.dataset.tok = textOf(node);
|
||||
box.dataset.kind = node.갈래 ?? "";
|
||||
box.dataset.eqVar = node.열쇠 ?? "";
|
||||
const value = eqText(node.값);
|
||||
@@ -269,17 +256,6 @@ function variable(node: EqNode, h: EqHandlers): HTMLElement {
|
||||
|
||||
function block(node: EqNode, h: EqHandlers): HTMLElement {
|
||||
const at = (h.blocks ?? []).push(node);
|
||||
if (node.기호) {
|
||||
// 801 — 로직 부름 = 기호(이름은 정의 영역 · 펼침 머리) · 누르면 펼침
|
||||
const sym = variable(
|
||||
{ ...node, 갈래: "블록" },
|
||||
{ onVar: h.onBlock ? () => h.onBlock?.(node) : undefined },
|
||||
);
|
||||
sym.dataset.tok = textOf(node);
|
||||
sym.dataset.eqBlock = node.열쇠 ?? "";
|
||||
sym.title = `${node.이름 ?? ""} ${eqText(node.값)}`.trim();
|
||||
return sym;
|
||||
}
|
||||
const value = eqText(node.값);
|
||||
const chip = span(
|
||||
"ui-eq__block",
|
||||
@@ -303,24 +279,14 @@ function block(node: EqNode, h: EqHandlers): HTMLElement {
|
||||
return chip;
|
||||
}
|
||||
|
||||
/** 고침 표지 — 감싸개 앞 · 뒤 글(그림에 안 보이는 식 조각) */
|
||||
const wrapped = (pre: string, post: string, kid: HTMLElement): HTMLElement => {
|
||||
const box = span("ui-eq__expr", kid);
|
||||
box.dataset.pre = pre;
|
||||
box.dataset.post = post;
|
||||
return box;
|
||||
};
|
||||
|
||||
/** 수식 나무 → 인라인 요소(`top` = 줄 맨 위 — 숨긴 감싸개 안 연산에 괄호 안 씀) */
|
||||
export function renderEq(node: EqNode | undefined, h: EqHandlers = {}, top = true): HTMLElement {
|
||||
/** 수식 나무 → 인라인 요소 */
|
||||
export function renderEq(node: EqNode | undefined, h: EqHandlers = {}): HTMLElement {
|
||||
if (!node) return span("ui-eq__expr");
|
||||
const sub = (child: EqNode | string | undefined): HTMLElement =>
|
||||
typeof child === "string" ? span("ui-eq__text", child) : renderEq(child, h, false);
|
||||
typeof child === "string" ? span("ui-eq__text", child) : renderEq(child, h);
|
||||
switch (node.꼴) {
|
||||
case "수": {
|
||||
const num = span("ui-eq__num", node.글 ?? "");
|
||||
return node.단위 ? span("ui-eq__expr", num, span("ui-eq__unit", node.단위)) : num;
|
||||
}
|
||||
case "수":
|
||||
return span("ui-eq__num", node.글 ?? "");
|
||||
case "글":
|
||||
return span("ui-eq__str", node.따옴 ? `'${node.글 ?? ""}'` : (node.글 ?? ""));
|
||||
case "변수":
|
||||
@@ -342,24 +308,17 @@ export function renderEq(node: EqNode | undefined, h: EqHandlers = {}, top = tru
|
||||
}
|
||||
case "괄호":
|
||||
return span("ui-eq__paren", span("ui-eq__inner", sub(node.안)));
|
||||
case "퍼센트": {
|
||||
const pct = span("ui-eq__op", "%");
|
||||
pct.dataset.tok = "/ 100";
|
||||
return span("ui-eq__expr", sub(node.안), pct);
|
||||
}
|
||||
case "퍼센트":
|
||||
return span("ui-eq__expr", sub(node.안), span("ui-eq__op", "%"));
|
||||
case "음":
|
||||
return span("ui-eq__expr", span("ui-eq__op", "−"), sub(node.안));
|
||||
case "조건": {
|
||||
if (taken(node)) {
|
||||
// 801-4 — 탄 갈래만(안 탄 갈래 · 조건은 안 보임 · 고칠 때 구조는 감싸개 글로 지킴)
|
||||
const [c, yes, no] = [node.조건, node.참, node.거짓].map((x) => textOf(x));
|
||||
return node.걸림 === 1
|
||||
? wrapped(`만약(${c}, `, `, ${no})`, sub(node.참))
|
||||
: wrapped(`만약(${c}, ${yes}, `, ")", sub(node.거짓));
|
||||
}
|
||||
const pick = node.걸림 ?? 0;
|
||||
const chip = span("ui-eq__cond", span("ui-eq__cond-key", "만약"), sub(node.조건));
|
||||
chip.title = `참 ${plainEq(node.참)} · 거짓 ${plainEq(node.거짓)}`;
|
||||
const all = span(
|
||||
if (pick === 1 || pick === 2)
|
||||
return span("ui-eq__expr", chip, sub(pick === 1 ? node.참 : node.거짓));
|
||||
return span(
|
||||
"ui-eq__expr",
|
||||
chip,
|
||||
span("ui-eq__op", "참"),
|
||||
@@ -367,20 +326,8 @@ export function renderEq(node: EqNode | undefined, h: EqHandlers = {}, top = tru
|
||||
span("ui-eq__op", "거짓"),
|
||||
sub(node.거짓),
|
||||
);
|
||||
all.dataset.tok = textOf(node);
|
||||
return all;
|
||||
}
|
||||
case "함수": {
|
||||
if (HIDDEN.has(node.이름 ?? "") && node.인자?.length) {
|
||||
// 801-2 — 반올림 · 자리 감싸개 안 보임(셈 그대로)
|
||||
const [first, ...rest] = node.인자;
|
||||
const inner =
|
||||
first?.꼴 === "연산" && !top
|
||||
? span("ui-eq__paren", span("ui-eq__inner", sub(first)))
|
||||
: sub(first);
|
||||
const tail = rest.map((x) => `, ${textOf(x)}`).join("");
|
||||
return wrapped(`${node.이름}(`, `${tail})`, inner);
|
||||
}
|
||||
const args = span("ui-eq__expr");
|
||||
(node.인자 ?? []).forEach((a, i) =>
|
||||
args.append(...(i ? [span("ui-eq__op", ","), sub(a)] : [sub(a)])),
|
||||
|
||||
@@ -5,18 +5,13 @@
|
||||
* 값 식이 결과와 같으면 값 식 칸 생략 · 식을 못 읽은 줄 = 원문 + 까닭(붉은 글)
|
||||
* 이음 = 여러 줄 위에서 아래로(`createEqChain`) · 하위 로직 부르기 = 줄 아래 접힘 블록(노 · 재 · 경 · 계 소계 · 펼치면 그 로직 줄 이음)
|
||||
* 크기 = 글 `--text-body` · 접힘 단추 22
|
||||
* 상태 = 바로 고침(801) — 기호 식을 누르면 그린 식 그대로 고침 자리(`onEdit(line, id, 누른 자리)` → 부르는 쪽이 `editing` 을 정해
|
||||
* 다시 그림 · `editor(line, id, host)` 가 그 자리에 고침을 붙임 · 호표는 수량 쪽만) · 값 식 숫자 · 중간 줄 결과 값 = 그 자리 숫자 고침(`onValue`)
|
||||
* · 펼친 블록 `data-open`
|
||||
* 801 = 박스 · 테두리 없는 조판 한 줄 · 한 마디 줄(서버 `한마디` — 표 찾기 · 요소 · 로직 부름 하나)은 「q = 0.7」(로직 부름은 아래 펼침 그대로)
|
||||
* 쓰는 법 = `createEqChain(tree.줄, { path: "", open: new Set(), onVar, editing, onEdit, editor, onValue })`
|
||||
* 상태 = 바로 고침 — 이름 식 칸을 누르면 그 자리가 식 칸으로 바뀜(`onEdit` → 부르는 쪽이 `editing` 을 정해 다시 그림 · `editor` 가 칸을 줌) · 펼친 블록 `data-open`
|
||||
* 쓰는 법 = `createEqChain(tree.줄, { path: "", open: new Set(), onVar, editing, onEdit, editor })`
|
||||
* 대신한 옛 변종 = 시트 줄(이름 | 식 | 값 한 줄 · 분수 · 풀이 없음 · 799-2 에 걷음) · 줄 눌러 여는 아래 편집 칸(800-3 에 걷음)
|
||||
* ========================================================================== */
|
||||
|
||||
import { createBadge } from "./ui_template_badge";
|
||||
import { createButton } from "./ui_template_button";
|
||||
import { editNumber } from "./ui_template_equation_edit";
|
||||
import { leavesOf } from "./ui_template_equation_text";
|
||||
import {
|
||||
eqText,
|
||||
plainEq,
|
||||
@@ -36,12 +31,10 @@ export interface EqLineOptions {
|
||||
onVar?: (node: EqNode) => void;
|
||||
/** 바로 고치는 줄 이름표(`lineId`) — 이 줄의 이름 식 칸 자리에 `editor` 칸이 들어감 */
|
||||
editing?: string | null;
|
||||
/** 기호 식을 누름(없으면 고칠 수 없음) — 누른 자리 */
|
||||
onEdit?: (line: EqLine, id: string, at: { x: number; y: number }) => void;
|
||||
/** 고치는 줄 — 그린 식(`host`)에 고침을 붙임 */
|
||||
editor?: (line: EqLine, id: string, host: HTMLElement) => void;
|
||||
/** 값 숫자를 고침 — `leaf` = 기호 식의 그 마디(수 · 변수) · 중간 줄 결과 값이면 줄 머리 */
|
||||
onValue?: (line: EqLine, leaf: EqNode, text: string) => void;
|
||||
/** 이름 식 칸을 누름(없으면 고칠 수 없음) */
|
||||
onEdit?: (line: EqLine, id: string) => void;
|
||||
/** 고치는 줄의 식 칸 */
|
||||
editor?: (line: EqLine, id: string) => HTMLElement;
|
||||
/** 줄 바로 아래에 끼울 것(하위 로직 블록 소계 묶음 · 800-4) */
|
||||
after?: (line: EqLine) => HTMLElement | null;
|
||||
/** 결과 줄 값 뒤 단위 */
|
||||
@@ -93,7 +86,7 @@ function blockPanel(node: EqNode, at: number, o: EqLineOptions): HTMLElement {
|
||||
box.dataset.eqBlockPanel = node.열쇠 ?? "";
|
||||
box.dataset.blockId = id;
|
||||
const head = createButton({
|
||||
label: `${node.기호 ? "" : `${String.fromCodePoint(0x245f + at)} `}${node.이름 || node.열쇠 || ""}`,
|
||||
label: `${String.fromCodePoint(0x245f + at)} ${node.이름 || node.열쇠 || ""}`,
|
||||
variant: "ghost",
|
||||
size: 22,
|
||||
iconStart: "chevronRight",
|
||||
@@ -117,8 +110,7 @@ function blockPanel(node: EqNode, at: number, o: EqLineOptions): HTMLElement {
|
||||
body.hidden = !on;
|
||||
};
|
||||
body.hidden = true;
|
||||
const sign = node.기호 ? [symbolOf(node), span("ui-eq__op", ":")] : [];
|
||||
box.append(div("ui-eq__block-row", ...sign, head, bundle(node)), body);
|
||||
box.append(div("ui-eq__block-row", head, bundle(node)), body);
|
||||
if (o.open.has(id)) toggle(true);
|
||||
return box;
|
||||
}
|
||||
@@ -140,36 +132,6 @@ function markOf(line: EqLine): HTMLElement | null {
|
||||
return box;
|
||||
}
|
||||
|
||||
/** 값 숫자 자리 — 누르면 그 자리 고침 */
|
||||
function valueSpot(num: HTMLElement, leaf: () => EqNode, line: EqLine, o: EqLineOptions): void {
|
||||
num.classList.add("is-value");
|
||||
num.title = "눌러서 값 고침";
|
||||
num.addEventListener("click", (ev) => {
|
||||
ev.stopPropagation();
|
||||
if (num.dataset.editing) return;
|
||||
const unit = [...num.querySelectorAll(".ui-eq__unit")];
|
||||
unit.forEach((u) => u.remove());
|
||||
// 결과 값 칸은 글 + 단위 — 글만 고침
|
||||
editNumber(num, (text) => o.onValue?.(line, leaf(), text));
|
||||
num.addEventListener("blur", () => num.append(...unit), { once: true });
|
||||
});
|
||||
}
|
||||
|
||||
/** 값 식 숫자 ↔ 기호 식 잎(같은 차례) — 수 · 입력 · 중간 · 표 찾기 · 요소만 고침(호표 단가 쪽 · 블록 · 금액 아님) */
|
||||
function values(box: HTMLElement, line: EqLine, o: EqLineOptions): void {
|
||||
const leaves = leavesOf(line.이름식);
|
||||
const skip = line.갈래 === "호표" ? leavesOf(line.이름식?.좌).length : 0;
|
||||
box.querySelectorAll<HTMLElement>(".ui-eq__num, .ui-eq__str").forEach((num, at) => {
|
||||
const leaf = leaves[at];
|
||||
const ok =
|
||||
at >= skip &&
|
||||
leaf &&
|
||||
(leaf.꼴 === "수" ||
|
||||
(leaf.꼴 === "변수" && ["입력", "중간", "찾기", "요소"].includes(leaf.갈래 ?? "")));
|
||||
if (ok && num.classList.contains("ui-eq__num")) valueSpot(num, () => leaf, line, o);
|
||||
});
|
||||
}
|
||||
|
||||
/** 줄 하나 */
|
||||
export function createEqLine(line: EqLine, o: EqLineOptions): HTMLElement {
|
||||
const id = lineId(line);
|
||||
@@ -212,38 +174,24 @@ export function createEqLine(line: EqLine, o: EqLineOptions): HTMLElement {
|
||||
line.글 || "—",
|
||||
...(resUnit ? [span("ui-eq__unit", resUnit)] : []),
|
||||
);
|
||||
if (o.onValue && line.갈래 === "중간" && head && line.글) valueSpot(result, () => head, line, o);
|
||||
const lone = line.한마디 && line.이름식;
|
||||
if (lone && line.이름식?.꼴 === "블록") blocks.push(line.이름식); // 펼침은 그대로
|
||||
if (line.이름식 && !lone) {
|
||||
if (line.이름식) {
|
||||
const name = span("ui-eq__box ui-eq__name");
|
||||
name.append(renderEq(line.이름식, hand));
|
||||
if (o.editing === id && o.editor) {
|
||||
name.classList.add("is-open");
|
||||
const expr = name.firstElementChild as HTMLElement;
|
||||
// 호표 = 단가 × 수량 — 수량 쪽만 고침
|
||||
const target = line.갈래 === "호표" ? (expr.lastElementChild as HTMLElement) : expr;
|
||||
const host = span("ui-eq__edit");
|
||||
target.replaceWith(host);
|
||||
host.append(target);
|
||||
o.editor(line, id, host);
|
||||
} else if (o.onEdit) {
|
||||
name.classList.add("is-edit");
|
||||
name.title = "눌러서 바로 고침 · 기호를 누르면 연결";
|
||||
name.addEventListener("click", (ev) =>
|
||||
o.onEdit?.(line, id, { x: ev.clientX, y: ev.clientY }),
|
||||
);
|
||||
name.append(o.editor(line, id));
|
||||
} else {
|
||||
name.append(renderEq(line.이름식, hand));
|
||||
if (o.onEdit) {
|
||||
name.classList.add("is-edit");
|
||||
name.title = "눌러서 바로 고침";
|
||||
name.addEventListener("click", () => o.onEdit?.(line, id));
|
||||
}
|
||||
}
|
||||
body.append(span("ui-eq__op", "="), name);
|
||||
const same =
|
||||
plainEq(line.값식) === (line.글 ?? "") || plainEq(line.값식) === plainEq(line.이름식);
|
||||
if (line.값식 && !same) {
|
||||
const val = span("ui-eq__box ui-eq__val", renderEq(line.값식));
|
||||
if (o.onValue) values(val, line, o);
|
||||
body.append(span("ui-eq__op", "="), val);
|
||||
}
|
||||
body.append(span("ui-eq__op", "="), result);
|
||||
} else if (lone) {
|
||||
if (line.값식 && !same)
|
||||
body.append(span("ui-eq__op", "="), span("ui-eq__box ui-eq__val", renderEq(line.값식)));
|
||||
body.append(span("ui-eq__op", "="), result);
|
||||
} else {
|
||||
body.append(
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
* 보이기 규칙 = `taken`(만약 = 탄 갈래만) · `HIDDEN`(반올림 = 자리 감싸개 숨김) — 셈 · 식은 그대로(그림만)
|
||||
* ========================================================================== */
|
||||
|
||||
import type { EqNode } from "./ui_template_equation";
|
||||
import type { EqNode as Base } from "./ui_template_equation";
|
||||
|
||||
/** 서버 마디 + 키보드 글(`입력글` · 별칭 꼴 · 없으면 식) */
|
||||
type EqNode = Base & { 입력글?: string };
|
||||
|
||||
/** 그림에서 감싸개를 숨기는 함수(첫 인자만 보임) */
|
||||
export const HIDDEN = new Set(["반올림"]);
|
||||
|
||||
Reference in New Issue
Block a user