clean.tpz
// List organizer. Paste many lines. It trims whitespace, removes duplicates, and sorts them. Written in Topaz.
// Key identifiers: 줄정리=escapeLine, 줄=line, 정리하기=organize,
// 텍스트=text, 줄목록=lines, 원시=raw, 다듬은=trimmed, 정렬됨=sorted,
// 고유목록=uniqueLines, 항목들=items, 결과=result
// 목록 정리기. 여러 줄을 붙여넣으면 공백 제거, 중복 제거, 정렬을 거칩니다. Topaz로 작성했습니다.
// 순수하고 결정적입니다. 같은 입력은 인터프리터와 네이티브/wasm 빌드에서 같은 HTML을 냅니다.
// Pure and deterministic. The same input yields the same HTML in the interpreter and the native/wasm builds.
// arr.sorted()(줄 정렬)와 str.byteLength()(빈 줄 제거), 그리고 문자열 기본 연산인
// split/trim/replace를 직접 사용합니다. 줄은 사용자 텍스트이므로 출력 전에 str.replace로 HTML 이스케이프합니다.
// Uses arr.sorted() (sort lines), str.byteLength() (drop empty lines), and the string builtins split/trim/replace directly.
// Lines are user text, so everything is HTML-escaped (via str.replace) before output.
function 줄정리(줄: string) -> string {
// & 를 먼저 치환해야 </> 가 이중 이스케이프되지 않습니다
// Replace & first so </> are not double-escaped.
줄.replace("&", "&").replace("<", "<").replace(">", ">")
}
function 정리하기(텍스트: string) -> string {
// 줄바꿈 기준으로 분리한 뒤 각 줄 공백을 제거하고 빈 줄(byteLength 0)을 버립니다
// Split on newlines, trim each line, and discard empty lines (byteLength 0).
let 줄목록 = 텍스트.split("\n").map(원시 => 원시.trim()).filter(다듬은 => 다듬은.byteLength() > 0)
// 오름차순으로 정렬한 뒤 인접 중복을 버립니다(같은 줄은 이제 이웃이 됩니다)
// Sort ascending, then drop adjacent duplicates (identical lines are now neighbors).
let 정렬됨 = 줄목록.sorted()
let mut 고유목록: Array<string> = []
for 줄 in 정렬됨 {
if 고유목록.get(고유목록.length - 1) != Some(줄) {
고유목록.push(줄)
}
}
// 각 고유 줄을 이스케이프해 <li>로 감싸고 목록을 조립합니다
// Escape each unique line, wrap in <li>, and assemble the ordered list.
let 항목들 = 고유목록.map(줄 => "<li>{줄정리(줄)}</li>").join("")
let 결과 = "<ol class=\"list\">{항목들}</ol>"
"<p class=\"meta\">원본 {줄목록.length}줄 → 고유 {고유목록.length}줄 (정렬·중복제거)</p>{결과}"
}
print(정리하기(input()))