1.무엇을 자동화할까 — 판단 기준
자동화는 사람이 손으로 하던 반복 작업을 코드가 대신하게 하는 일입니다. 거창한 프로그램이 아니어도 됩니다. 매주 받는 판매 기록에서 품목별 합계를 내거나, 여기저기서 모은 명단의 띄어쓰기와 중복을 정리하는 수십 줄짜리 코드도 훌륭한 자동화입니다.
다만 모든 일을 코드로 바꿀 필요는 없습니다. 한 번만 하는 일이고 10분이면 끝난다면 코드를 짜고 확인하는 시간이 더 걸릴 수 있습니다. 반대로 한 번에 10분 걸리는 일을 매주 한다면 1년에 520분, 약 9시간입니다. 같은 규칙으로 되풀이되고, 양이 많고, 손으로 하면 실수가 잦은 일일수록 자동화할 가치가 큽니다.
규칙이 분명한지도 중요합니다. '전화번호에서 숫자만 남겨 010-0000-0000 모양으로 바꾼다'는 규칙은 코드로 쓰기 쉽습니다. 하지만 '어색한 문장을 자연스럽게 고친다'처럼 판단이 필요한 일은 코드보다 사람이나 AI 도우미의 검토가 맞습니다. 규칙을 말로 또박또박 적을 수 있으면 코드로도 쓸 수 있다는 1강의 생각이 여기서도 그대로 통합니다.
| 기준 | 스스로 묻는 질문 | 자동화 쪽으로 기우는 신호 |
|---|---|---|
| 반복 | 얼마나 자주 하는가 | 매일·매주·매달 되풀이된다 |
| 규칙 | 처리 규칙을 말로 적을 수 있는가 | 예외까지 몇 줄로 정리된다 |
| 양 | 한 번에 몇 건을 다루는가 | 수십 건 이상이라 눈으로 보기 힘들다 |
| 실수 비용 | 틀리면 얼마나 곤란한가 | 손으로 할 때 빠뜨림·오타가 자주 난다 |
| 변화 | 입력 모양이 자주 바뀌는가 | 열 순서·형식이 거의 그대로다 |
2.쉼표로 나뉜 텍스트를 표로 바꾸기
표 계산 프로그램에서 내려받은 자료나 메신저로 받은 목록은 흔히 한 줄에 한 건, 칸은 쉼표로 나뉜 모양입니다. 이런 형식을 CSV(Comma-Separated Values, 쉼표로 구분한 값)라고 부릅니다. 첫 줄은 보통 열 이름(머리글)이고, 둘째 줄부터가 실제 기록입니다.
코드로 바꾸는 순서는 단순합니다. 먼저 7강에서 배운 split("\n")으로 줄을 나누고, 각 줄을 다시 split(",")으로 칸을 나눕니다. 그다음 6강의 객체로 칸마다 이름을 붙이면 '객체의 배열', 즉 코드 안의 표가 됩니다. 앞뒤 빈 줄 때문에 빈 기록이 생기지 않도록 trim()을 먼저 해 두는 것이 좋습니다.
중요한 함정이 하나 있습니다. split으로 나눈 칸은 모두 문자열입니다. 숫자처럼 보여도 "10"은 문자열이므로 그대로 더하면 2강에서 본 것처럼 이어 붙여집니다. 수량·금액 칸은 Number()로 바꿔 두어야 계산이 맞습니다.
slice(1)로 건너뜁니다.const text = `날짜,품목,수량,단가
2026-03-01,연필,10,500
2026-03-01,공책,3,2000
2026-03-02,연필,5,500
2026-03-02,지우개,4,300`;
const lines = text.trim().split("\n");
console.log(lines[0].split(","));
const rows = lines.slice(1).map((line) => {
const c = line.split(",");
return {
date: c[0],
item: c[1],
qty: Number(c[2]),
price: Number(c[3]),
};
});
console.log(rows.length);
console.log(rows[0]);[ '날짜', '품목', '수량', '단가' ]
4
{ date: '2026-03-01', item: '연필', qty: 10, price: 500 }+는 이어 붙이기입니다. 숫자가 아닌 글자가 섞이면 Number는 NaN을 돌려줍니다.const c = "2026-03-01,연필,10,500".split(",");
console.log(c[2] + c[3]);
console.log(Number(c[2]) * Number(c[3]));
console.log(Number("10개"));10500 5000 NaN
3.합계·평균·그룹별 합계
표가 생기면 4강의 누적 패턴으로 합계를 냅니다. 변수 하나를 0으로 두고 기록을 하나씩 돌며 더하면 됩니다. 평균은 합계를 기록 수로 나눈 값인데, 기록이 0건이면 0으로 나누게 되어 NaN이 나오므로 먼저 확인합니다. 소수가 길게 나오면 Math.round(x * 10) / 10처럼 반올림 자리를 정해 둡니다.
'품목별 합계', '부서별 경비'처럼 무리마다 따로 더하는 것을 그룹별 합계라고 합니다. 빈 객체를 하나 만들고, 기록마다 그 무리 이름을 키로 써서 값을 더합니다. 처음 보는 키는 값이 undefined이므로 (합[키] || 0) + 값처럼 0에서 시작하게 하는 것이 요령입니다. 표 계산 프로그램의 피벗 표가 하는 일을 몇 줄로 직접 해 보는 셈입니다.
계산이 끝나면 숫자 하나를 반드시 손으로 검산합니다. 아래 예에서 연필은 10개×500원과 5개×500원이므로 7,500원이어야 합니다. 이렇게 한 무리라도 직접 맞춰 보면 열을 잘못 고르거나 문자열을 숫자로 바꾸지 않은 실수를 바로 잡을 수 있습니다.
const rows = [
{ item: "연필", qty: 10, price: 500 },
{ item: "공책", qty: 3, price: 2000 },
{ item: "연필", qty: 5, price: 500 },
{ item: "지우개", qty: 4, price: 300 },
];
let total = 0;
let qtySum = 0;
const byItem = {};
for (const r of rows) {
const amount = r.qty * r.price;
total += amount;
qtySum += r.qty;
byItem[r.item] = (byItem[r.item] || 0) + amount;
}
console.log("총매출", total);
console.log("평균 수량", qtySum / rows.length);
console.log(byItem);총매출 14700
평균 수량 5.5
{ '연필': 7500, '공책': 6000, '지우개': 1200 }const text = `부서,금액
영업,32000
개발,15000
총무,9000
영업,18000
개발,26000`;
const sums = {};
for (const line of text.split("\n").slice(1)) {
const [team, money] = line.split(",");
sums[team] = (sums[team] || 0) + Number(money);
}
console.log(sums);
let best = null;
for (const [team, sum] of Object.entries(sums)) {
if (best === null || sum > best[1]) {
best = [team, sum];
}
}
console.log("가장 많이 쓴 부서", best[0]);{ '영업': 50000, '개발': 41000, '총무': 9000 }
가장 많이 쓴 부서 영업- 1단계 텍스트를 줄로 나누고 머리글을 건너뜁니다.
- 2단계 각 줄을 쉼표로 나눠 부서와 금액을 꺼내고, 금액은
Number로 바꿉니다. 코드의const [team, money] = …는 나눈 배열의 첫째·둘째 값을 차례로 두 이름에 담는 문법(구조 분해 할당)입니다. - 3단계 빈 객체에 부서 이름을 키로 금액을 더합니다.
- 4단계
Object.entries로 객체를[부서, 합계]쌍의 배열로 바꾸고, 반복하며 가장 큰 값을 기억합니다. - 검산: 영업은 32,000 + 18,000 = 50,000원으로 코드 결과와 같은지 확인합니다.
4.텍스트 정리 — 공백·빈 줄·중복
여러 사람이 손으로 입력한 명단에는 앞뒤 공백, 두 칸 띄어쓰기, 빈 줄, 같은 사람이 두 번 들어간 줄이 흔히 섞여 있습니다. 눈으로는 같아 보여도 컴퓨터에게 "민수"와 "민수 "는 다른 문자열이라, 정리하지 않으면 중복 제거나 검색이 제대로 되지 않습니다.
정리 규칙은 대개 세 단계입니다. trim()으로 앞뒤 공백을 지우고, replace(/\s+/g, " ")로 연속된 공백을 한 칸으로 줄이고, filter로 빈 문자열을 뺍니다. \s+는 '공백 문자가 하나 이상'이라는 정규식으로, 7강에서 맛본 것입니다. 정규식이 헷갈리면 정규표현식 테스터에 예시 문장을 넣어 무엇이 걸리는지 먼저 보세요.
중복 제거에는 Set이 편합니다. Set은 같은 값을 한 번만 담는 묶음이라 [...new Set(배열)]로 다시 배열로 펼치면 처음 나온 순서대로 중복이 빠집니다. 전자우편 주소처럼 보통 대소문자를 구별하지 않고 다루는 값은 toLowerCase()로 먼저 맞춘 다음 중복을 빼야 합니다. 정리 전후의 개수를 같이 찍어 두면 몇 건이 빠졌는지 바로 보입니다.
const raw = [
" 민수 ",
"서 연",
"민수",
"",
"지훈 ",
"서 연",
];
const cleaned = raw
.map((s) => s.trim().replace(/\s+/g, " "))
.filter((s) => s !== "");
console.log(cleaned);
const unique = [...new Set(cleaned)];
console.log(unique);
console.log(raw.length, "→", unique.length);[ '민수', '서 연', '민수', '지훈', '서 연' ] [ '민수', '서 연', '지훈' ] 6 → 3
const emails = ["[email protected]", "[email protected] "];
const norm = emails.map((e) => e.trim().toLowerCase());
console.log([...new Set(norm)]);[ '[email protected]' ]
5.전화번호·날짜 형식 통일하기
같은 전화번호도 010-1234-5678, 01012345678, 010 1234 5678처럼 여러 모양으로 들어옵니다. 형식을 통일하는 가장 튼튼한 방법은 '숫자만 남긴 뒤 다시 조립하기'입니다. replace(/\D/g, "")는 숫자가 아닌 글자를 모두 지웁니다. 남은 숫자가 11자리이고 01로 시작하면 3-4-4로 끊어 하이픈을 넣습니다.
규칙에 맞지 않는 값은 억지로 고치지 말고 null처럼 '처리 못 함'을 돌려주는 것이 좋습니다. 그래야 나중에 그 줄만 모아 사람이 확인할 수 있습니다. 자동화가 모르는 값을 그럴듯하게 바꿔 버리면 틀린 자료가 조용히 섞이고, 이것이 손으로 한 실수보다 찾기 어렵습니다.
날짜도 2026.3.5., 2026/03/05, 2026-3-15 처럼 제각각입니다. 공백과 끝의 점을 지우고 .·/·- 중 무엇으로든 나눈 다음, 월과 일을 padStart(2, "0")으로 두 자리로 맞춰 2026-03-05 모양으로 만듭니다. 이 모양은 문자열로 정렬해도 날짜 순서가 되어 편합니다. 아래 함수는 월 1~12, 일 1~31만 확인하므로 2월 30일 같은 날짜는 걸러 내지 못합니다. 이런 한계는 주석으로 남겨 둡니다.
null로 표시해 따로 확인합니다.function formatPhone(s) {
const d = s.replace(/\D/g, "");
if (d.length !== 11 || !d.startsWith("01")) {
return null;
}
return d.slice(0, 3) + "-" + d.slice(3, 7) +
"-" + d.slice(7);
}
const inputs = [
"010-1234-5678",
"01012345678",
"010 1234 5678",
"(010)1234.5678",
"1234-5678",
];
for (const p of inputs) {
console.log(p, "→", formatPhone(p));
}010-1234-5678 → 010-1234-5678 01012345678 → 010-1234-5678 010 1234 5678 → 010-1234-5678 (010)1234.5678 → 010-1234-5678 1234-5678 → null
3/5/2026처럼 순서가 다른 형식은 연도 자리가 맞지 않아 null이 됩니다.// 월 1~12, 일 1~31만 확인한다(2월 30일은 못 거름)
function formatDate(s) {
const t = s.replace(/\s/g, "").replace(/\.$/, "");
const parts = t.split(/[.\/-]/).map(Number);
if (parts.length !== 3) return null;
const y = parts[0], m = parts[1], d = parts[2];
if (!Number.isInteger(y) || y < 1000) return null;
if (!(m >= 1 && m <= 12 && d >= 1 && d <= 31)) {
return null;
}
const mm = String(m).padStart(2, "0");
const dd = String(d).padStart(2, "0");
return y + "-" + mm + "-" + dd;
}
const dates = [
"2026.3.5.",
"2026/03/05",
" 2026-3-15 ",
"2026. 12. 1",
"2026.13.1",
"3/5/2026",
];
for (const x of dates) {
console.log(JSON.stringify(x), "→", formatDate(x));
}"2026.3.5." → 2026-03-05 "2026/03/05" → 2026-03-05 " 2026-3-15 " → 2026-03-15 "2026. 12. 1" → 2026-12-01 "2026.13.1" → null "3/5/2026" → null
6.원본을 지키고 결과를 확인하기
자동화에서 가장 큰 사고는 원본을 덮어써서 되돌릴 수 없게 되는 것입니다. 코드는 원본을 읽기만 하고 결과는 새 변수나 새 파일에 쓰는 것을 원칙으로 합니다. 파일을 다룬다면 작업 전에 원본을 따로 복사해 두고, 결과 파일 이름에 날짜나 '정리본'을 붙여 구별합니다. 6강에서 본 것처럼 map·filter는 새 배열을 만들고 원래 배열은 그대로 두므로 이 원칙에 잘 맞습니다.
결과는 세 가지로 확인합니다. 첫째, 개수 확인입니다. 원본 기록 수, 결과 기록 수, 걸러 낸 수를 찍어 더하면 맞는지 봅니다. 둘째, 표본 확인입니다. 결과에서 몇 줄을 골라 원본과 손으로 비교하고, 특히 맨 처음·맨 끝·이상해 보이는 줄을 봅니다. 셋째, 합계 확인입니다. 표 계산 프로그램으로 낸 합계와 코드의 합계가 같은지 맞춰 봅니다. 정리 전후 텍스트를 텍스트 비교기에 넣으면 바뀐 곳만 한눈에 볼 수 있습니다.
실제 CSV 파일에는 이 강의의 단순한 split(",")이 깨지는 경우가 있습니다. 칸 안에 쉼표가 들어가면 그 칸을 큰따옴표로 감싸는 규칙이 있어서, "연필, 파랑"처럼 쓰인 한 칸이 두 칸으로 잘려 버립니다. 칸 안의 줄바꿈, 따옴표 안의 따옴표 같은 규칙도 있습니다. 그래서 진짜 파일을 다룰 때는 표 계산 프로그램으로 열어 처리하거나, CSV 규칙을 제대로 구현한 검증된 라이브러리(파서)를 씁니다. 이 강의의 방식은 형식을 직접 정한 단순한 텍스트에 알맞습니다.
split이 모릅니다.const line = '2026-03-03,"연필, 파랑",2,500';
const cells = line.split(",");
console.log(cells.length);
console.log(cells);5 [ '2026-03-03', '"연필', ' 파랑"', '2', '500' ]
\r\n입니다. 이상한 줄은 버리지 말고 '보류'로 모아 사람이 봅니다.const text = "이름,금액\r\n민수,3000\r\n\r\n서연,abc\r\n";
const lines = text.split(/\r?\n/).slice(1);
const ok = [];
const bad = [];
for (const line of lines) {
if (line.trim() === "") continue;
const c = line.split(",");
const n = Number(c[1]);
if (c.length === 2 && Number.isFinite(n)) {
ok.push({ name: c[0], amount: n });
} else {
bad.push(line);
}
}
console.log("처리", ok.length, "보류", bad.length);
console.log(bad);처리 1 보류 1 [ '서연,abc' ]
- 원본은 읽기만 하고, 결과는 새 변수·새 파일에 쓴다
- 원본 수 = 처리 수 + 보류 수인지 확인한다
- 처음·끝·이상한 줄을 골라 손으로 비교한다
- 합계 하나는 다른 방법(계산기·표 계산 프로그램)으로 검산한다
- 진짜 CSV 파일은 표 계산 프로그램이나 검증된 CSV 파서로 다룬다
7.AI 도우미와 함께 자동화 만들기
자동화 코드는 AI 코딩 도우미에게 맡기기 좋은 일입니다. 다만 좋은 결과를 받으려면 입력 모양, 원하는 출력, 예외 처리 규칙을 분명히 말해야 합니다. 'CSV 정리해 줘'보다 '머리글이 부서,금액인 텍스트에서 부서별 합계를 객체로 돌려주는 함수, 금액이 숫자가 아닌 줄은 따로 모아 줘'가 훨씬 정확한 코드를 받습니다.
AI에게 자료를 보여 줄 때는 실제 고객 명단·연락처를 붙여 넣지 말고, 같은 모양의 가짜 자료 몇 줄만 보여 줍니다. 형식만 알면 코드는 만들 수 있기 때문입니다. 받은 코드는 내 컴퓨터에서 진짜 자료로 돌리고, 위의 개수·표본·합계 확인을 똑같이 합니다.
받은 코드가 맞는지 읽고 테스트하는 방법은 다음 10강에서 자세히 다룹니다. 이번 강의의 실습 문제를 직접 풀어 본 경험이 있으면, AI가 짠 코드에서 Number 변환이 빠졌거나 빈 줄을 처리하지 않은 곳이 훨씬 잘 보입니다.
📌 핵심 정리
- 자주 반복되고, 규칙이 분명하고, 양이 많고, 실수가 잦은 일이 자동화 후보다
- 줄은
split("\n"), 칸은split(",")으로 나누고 숫자 칸은Number로 바꾼다 - 그룹별 합계는 빈 객체에
(합[키] || 0) + 값으로 쌓는다 - 정리 규칙에 맞지 않는 값은 억지로 고치지 말고
null·보류로 표시한다 - 원본은 지키고, 개수·표본·합계로 결과를 확인하며, 진짜 CSV 파일은 전용 파서나 표 계산 프로그램으로 다룬다
🧪 코드 실습
가상의 기록으로 작은 자동화 함수를 만들어 봅니다. 빈 자료나 형식이 틀린 값 같은 경계 경우도 테스트에 들어 있습니다.
코드는 이 브라우저 안의 격리된 공간에서만 실행되고 서버로 보내지 않습니다. 네트워크에는 접속할 수 없고, 2초가 넘으면 멈춥니다. 고친 코드는 이 브라우저에만 저장됩니다. Ctrl+Enter(⌘+Enter)로 실행하고, Tab 키는 공백 두 칸입니다(Esc 다음 Tab 은 다음 칸으로 이동).
자바스크립트가 꺼져 있어 실행할 수는 없지만, 문제와 처음 코드, 자동 검사 내용, 예시 답안은 그대로 읽을 수 있습니다.
1금액 합계 내기
함수 totalAmount(text)를 완성하세요. text는 첫 줄이 머리글 이름,금액이고 둘째 줄부터 이름,금액 기록이 이어지는 문자열입니다. 모든 금액의 합을 숫자로 돌려주세요. 기록이 없으면 0, 빈 줄은 건너뜁니다.
totalAmount("이름,금액\n민수,3000\n서연,4500")기대값7500totalAmount("이름,금액\n지훈,1200\n\n민수,800\n")기대값2000totalAmount("이름,금액")기대값0totalAmount("이름,금액\n서연,0\n지훈,250")기대값250
💡 힌트
c[1]은 문자열입니다. Number(c[1])로 바꿔 더하고, line.trim() === ""이면 continue로 넘어가세요.
예시 답안 보기
function totalAmount(text) {
const lines = text.split("\n").slice(1);
let total = 0;
for (const line of lines) {
if (line.trim() === "") continue;
const c = line.split(",");
total += Number(c[1]);
}
return total;
}2명단 정리하기
함수 cleanNames(list)를 완성하세요. 문자열 배열을 받아 각 이름의 앞뒤 공백을 지우고 연속된 공백을 한 칸으로 줄인 뒤, 빈 이름을 빼고 중복을 없앤 배열을 돌려주세요. 순서는 처음 나온 순서를 지킵니다.
cleanNames([" 민수 ","서연","민수"])기대값["민수","서연"]cleanNames(["김 지훈","김 지훈 ",""])기대값["김 지훈"]cleanNames([])기대값[]cleanNames([" ","","하나"])기대값["하나"]cleanNames(["서연","민수","서연","민수"])기대값["서연","민수"]
💡 힌트
replace(/\s+/g, " ")로 공백을 줄이고 filter로 빈 문자열을 뺀 다음 [...new Set(배열)]로 중복을 없앱니다.
예시 답안 보기
function cleanNames(list) {
const cleaned = list
.map((s) => s.trim().replace(/\s+/g, " "))
.filter((s) => s !== "");
return [...new Set(cleaned)];
}3전화번호 형식 통일
함수 formatPhone(s)를 완성하세요. 문자열에서 숫자만 남겼을 때 11자리이고 01로 시작하면 010-1234-5678 모양(3-4-4)으로 돌려주고, 그렇지 않으면 null을 돌려주세요.
formatPhone("01012345678")기대값"010-1234-5678"formatPhone("010 9876 5432")기대값"010-9876-5432"formatPhone("(010)1111.2222")기대값"010-1111-2222"formatPhone("1234-5678")기대값nullformatPhone("")기대값nullformatPhone("02-123-45678")기대값null
💡 힌트
s.replace(/\D/g, "")가 숫자만 남깁니다. d.length !== 11 || !d.startsWith("01")이면 null입니다.
예시 답안 보기
function formatPhone(s) {
const d = s.replace(/\D/g, "");
if (d.length !== 11 || !d.startsWith("01")) {
return null;
}
return d.slice(0, 3) + "-" + d.slice(3, 7) +
"-" + d.slice(7);
}4그룹별 합계
함수 sumByGroup(text)를 완성하세요. text는 첫 줄이 머리글 부서,금액인 여러 줄 문자열입니다. 부서 이름을 키, 그 부서 금액의 합을 값으로 하는 객체를 돌려주세요. 기록이 없으면 빈 객체 {}, 빈 줄은 건너뜁니다.
sumByGroup("부서,금액\n영업,100\n개발,200\n영업,50")기대값{"개발":200,"영업":150}sumByGroup("부서,금액")기대값{}sumByGroup("부서,금액\n총무,0\n\n총무,30\n")기대값{"총무":30}sumByGroup("부서,금액\n개발,10\n개발,20\n개발,30")기대값{"개발":60}
💡 힌트
지금 코드는 같은 부서가 다시 나오면 앞의 값을 덮어씁니다. (sums[c[0]] || 0) + Number(c[1])로 더해 가세요.
예시 답안 보기
function sumByGroup(text) {
const sums = {};
const lines = text.split("\n").slice(1);
for (const line of lines) {
if (line.trim() === "") continue;
const c = line.split(",");
sums[c[0]] = (sums[c[0]] || 0) + Number(c[1]);
}
return sums;
}🤖 AI에게 이렇게 물어보세요
복사해서 [ ] 부분을 내 상황으로 바꿔 쓰세요. 답을 그대로 믿지 말고 본문과 비교해 확인하세요.
반복 작업을 코드로 바꾸고 싶을 때
나는 매주 [작업 설명]을 손으로 하고 있어. 입력은 아래 가짜 예시와 같은 모양이고, 출력은 [원하는 결과 모양]이면 좋겠어. JavaScript 함수로 짜 주고, 숫자로 바꿀 칸, 빈 줄, 형식이 틀린 줄을 어떻게 처리하는지 주석으로 밝혀 줘. 형식이 틀린 줄은 버리지 말고 따로 모아 줘. [가짜 예시 3~5줄]
만든 자동화 코드를 점검받고 싶을 때
아래는 CSV 비슷한 텍스트를 정리하는 내 JavaScript 코드야. 원본을 바꾸는 부분이 있는지, 문자열을 숫자로 안 바꾼 곳이 있는지, 칸 안의 쉼표·빈 줄·줄 끝 `\r` 같은 경우에 어떻게 되는지 짚어 주고, 확인용 테스트 입력 5개를 만들어 줘. [내 코드]
정리 규칙을 정하고 싶을 때
[전화번호/날짜/이름] 칸이 사람마다 다른 모양으로 입력돼 있어. 아래 가짜 예시들을 보고 하나로 통일할 규칙을 제안해 주고, 규칙에 맞지 않아 사람이 확인해야 할 경우를 목록으로 정리해 줘. [가짜 예시]
🧰 관련 도구
이 강의에서 다룬 JSON·정규식·텍스트를 바로 확인하고 다듬어 볼 수 있는 도구입니다. 실제 개인정보나 비밀번호는 붙여 넣지 마세요.
- MDN Web Docs — JavaScript 안내서(Guide)와 String·Array·Set·Object.entries 참조 문서
- RFC 4180 — CSV 형식(쉼표·큰따옴표·줄바꿈 규칙)에 관한 일반적 설명
학습 목표를 모두 이뤘다면 완료를 눌러 진도에 기록하세요.
이 브라우저에서는 저장할 수 없어 이 화면에서만 표시됩니다.