<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CHARACTER ARCHIVE</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
background: #f3f3f3;
color: #292929;
font-family: Arial, "Malgun Gothic", sans-serif;
}
header {
padding: 25px 20px;
background: white;
border-bottom: 1px solid #ddd;
}
header small {
color: #888;
letter-spacing: 3px;
}
header h1 {
margin: 12px 0 5px;
font-size: 24px;
}
header p {
color: #888;
font-size: 12px;
}
main {
max-width: 1050px;
margin: 25px auto;
padding: 0 15px;
display: grid;
grid-template-columns: minmax(0, 1fr) 340px;
gap: 25px;
align-items: start;
}
.editor {
background: white;
border: 1px solid #ddd;
padding: 22px;
min-width: 0;
}
.title {
color: #888;
font-size: 11px;
letter-spacing: 2px;
margin: 25px 0 15px;
}
.title:first-child {
margin-top: 0;
}
label {
display: block;
font-size: 12px;
color: #666;
margin-bottom: 7px;
}
input, textarea {
display: block;
width: 100%;
padding: 12px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 3px;
background: #fafafa;
color: #292929;
font: inherit;
font-size: 13px;
}
textarea {
min-height: 75px;
resize: vertical;
line-height: 1.7;
}
input:focus, textarea:focus {
outline: none;
border-color: #555;
background: white;
}
.row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.upload {
border: 1px dashed #aaa;
padding: 15px;
text-align: center;
cursor: pointer;
font-size: 12px;
}
.upload input {
display: none;
}
button {
cursor: pointer;
font: inherit;
font-size: 12px;
}
.btn {
width: 100%;
padding: 14px;
margin-top: 8px;
border: none;
font-weight: bold;
}
.black {
background: #292929;
color: white;
}
.gray {
background: #eee;
color: #333;
}
.red {
background: #f5e9e9;
color: #8d3333;
}
#status {
font-size: 11px;
line-height: 1.8;
color: #666;
overflow-wrap: anywhere;
margin-top: 15px;
}
.library {
border-top: 1px solid #ddd;
margin-top: 25px;
padding-top: 20px;
}
.library-head {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
font-size: 12px;
}
.library-head span {
color: #888;
}
#list {
display: grid;
gap: 8px;
}
.item {
display: flex;
gap: 10px;
align-items: center;
padding: 10px;
border: 1px solid #ddd;
}
.item.active {
border-color: #333;
}
.item-open {
display: flex;
align-items: center;
gap: 10px;
flex: 1;
min-width: 0;
text-align: left;
border: none;
background: white;
}
.thumb {
width: 42px;
height: 48px;
object-fit: cover;
background: #eee;
flex-shrink: 0;
}
.item-name {
font-weight: bold;
font-size: 12px;
overflow-wrap: anywhere;
}
.item-info {
color: #888;
font-size: 10px;
margin-top: 5px;
}
.delete-small {
border: none;
background: white;
color: #999;
padding: 7px;
}
.empty {
text-align: center;
padding: 20px 5px;
color: #999;
font-size: 12px;
line-height: 1.8;
}
/* 프로필 카드 */
.preview {
position: sticky;
top: 15px;
min-width: 0;
}
.preview-label {
text-align: center;
font-size: 10px;
letter-spacing: 3px;
color: #888;
margin-bottom: 12px;
}
#profile {
background: white;
border: 1px solid #ddd;
overflow: hidden;
}
.cover {
height: 9px;
background: #292929;
}
.photo {
height: 280px;
background: #eee;
position: relative;
}
.photo img {
width: 100%;
height: 100%;
display: none;
object-fit: cover;
}
.placeholder {
position: absolute;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
color: #999;
}
.placeholder strong {
font-size: 35px;
font-weight: normal;
}
.placeholder span {
font-size: 9px;
letter-spacing: 3px;
margin-top: 8px;
}
.content {
padding: 23px;
}
.eyebrow {
color: #999;
font-size: 9px;
letter-spacing: 3px;
margin-bottom: 12px;
}
#o-name {
font-size: 27px;
margin: 0;
line-height: 1.4;
overflow-wrap: anywhere;
}
#o-sub {
font-size: 11px;
color: #888;
margin-top: 7px;
}
.line {
border: 0;
border-top: 1px solid #eee;
margin: 20px 0;
}
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px 12px;
}
.info-label {
color: #999;
font-size: 9px;
letter-spacing: 1px;
margin-bottom: 6px;
}
.info-value {
font-size: 12px;
line-height: 1.7;
white-space: pre-wrap;
overflow-wrap: anywhere;
min-height: 15px;
}
.detail {
margin-top: 23px;
}
.detail-title {
color: #888;
font-size: 10px;
letter-spacing: 2px;
margin-bottom: 9px;
}
.detail-text {
font-size: 11px;
line-height: 1.9;
white-space: pre-wrap;
overflow-wrap: anywhere;
color: #444;
}
.footer {
border-top: 1px solid #eee;
margin-top: 25px;
padding-top: 13px;
display: flex;
justify-content: space-between;
color: #aaa;
font-size: 8px;
letter-spacing: 1px;
}
@media (max-width: 740px) {
main {
grid-template-columns: minmax(0, 1fr);
padding: 0 12px;
}
.preview {
position: static;
grid-row: 1;
width: 100%;
max-width: 350px;
margin: auto;
}
.editor {
padding: 17px;
}
}
</style>
</head>
<body>
<header>
<small>C / A — CHARACTER ARCHIVE</small>
<h1>캐릭터 프로필 제작실</h1>
<p>당신의 캐릭터를 한 장의 기록으로.</p>
</header>
<main>
<section class="editor">
<div class="title">01 — IMAGE</div>
<label class="upload">
+ 캐릭터 사진 선택하기
<input type="file" id="photo" accept="image/*">
</label>
<button class="btn gray" id="removePhoto">
사진 제거
</button>
<div class="title">02 — BASIC INFORMATION</div>
<label for="name">이름 NAME</label>
<input id="name" placeholder="캐릭터 이름">
<div class="row">
<div>
<label for="age">나이 AGE</label>
<input id="age" placeholder="예: 24세">
</div>
<div>
<label for="gender">성별 GENDER</label>
<input id="gender" placeholder="성별">
</div>
</div>
<div class="row">
<div>
<label for="height">키 HEIGHT</label>
<input id="height" placeholder="예: 172cm">
</div>
<div>
<label for="job">직업 JOB</label>
<input id="job" placeholder="직업">
</div>
</div>
<label for="affiliation">소속 AFFILIATION</label>
<input id="affiliation" placeholder="회사, 팀, 조직 등">
<div class="title">03 — CHARACTER DETAILS</div>
<label for="personality">성격 PERSONALITY</label>
<textarea id="personality" placeholder="성격과 말투"></textarea>
<label for="feature">특징 FEATURES</label>
<textarea id="feature" placeholder="외모, 능력, 습관"></textarea>
<label for="likes">좋아하는 것 LIKE</label>
<textarea id="likes" placeholder="좋아하는 음식, 취미 등"></textarea>
<label for="dislikes">싫어하는 것 DISLIKE</label>
<textarea id="dislikes" placeholder="싫어하는 것"></textarea>
<label for="story">과거 및 서사 BACKGROUND</label>
<textarea id="story" placeholder="캐릭터의 과거와 이야기"></textarea>
<label for="etc">기타 설정 OTHER</label>
<textarea id="etc" placeholder="그 밖의 설정"></textarea>
<button class="btn black" id="save">캐릭터 저장</button>
<button class="btn gray" id="new">+ 새 캐릭터 작성</button>
<button class="btn black" id="png">↓ PNG 이미지 저장</button>
<button class="btn red" id="delete">현재 캐릭터 삭제</button>
<div id="status" role="status" aria-live="polite">
새 캐릭터를 작성해 주세요.
</div>
<div class="library">
<div class="library-head">
<strong>CHARACTER LIBRARY</strong>
<span id="count">0 CHARACTERS</span>
</div>
<div id="list"></div>
</div>
</section>
<section class="preview">
<div class="preview-label">LIVE PREVIEW</div>
<div id="profile">
<div class="cover"></div>
<div class="photo">
<img id="o-photo" alt="캐릭터 사진">
<div class="placeholder" id="placeholder">
<strong>+</strong>
<span>CHARACTER IMAGE</span>
</div>
</div>
<div class="content">
<div class="eyebrow">CHARACTER FILE</div>
<h2 id="o-name">이름을 입력하세요</h2>
<div id="o-sub">CHARACTER PROFILE</div>
<hr class="line">
<div class="info-grid">
<div>
<div class="info-label">AGE</div>
<div class="info-value" id="o-age">—</div>
</div>
<div>
<div class="info-label">GENDER</div>
<div class="info-value" id="o-gender">—</div>
</div>
<div>
<div class="info-label">HEIGHT</div>
<div class="info-value" id="o-height">—</div>
</div>
<div>
<div class="info-label">OCCUPATION</div>
<div class="info-value" id="o-job">—</div>
</div>
<div style="grid-column:1/-1">
<div class="info-label">AFFILIATION</div>
<div class="info-value" id="o-affiliation">—</div>
</div>
</div>
<div class="detail">
<div class="detail-title">PERSONALITY</div>
<div class="detail-text" id="o-personality">—</div>
</div>
<div class="detail">
<div class="detail-title">FEATURES</div>
<div class="detail-text" id="o-feature">—</div>
</div>
<div class="detail">
<div class="detail-title">LIKE</div>
<div class="detail-text" id="o-likes">—</div>
</div>
<div class="detail">
<div class="detail-title">DISLIKE</div>
<div class="detail-text" id="o-dislikes">—</div>
</div>
<div class="detail">
<div class="detail-title">BACKGROUND</div>
<div class="detail-text" id="o-story">—</div>
</div>
<div class="detail">
<div class="detail-title">OTHER INFORMATION</div>
<div class="detail-text" id="o-etc">—</div>
</div>
<div class="footer">
<span>CHARACTER ARCHIVE</span>
<span>CONFIDENTIAL</span>
</div>
</div>
</div>
</section>
</main>
<script>
(function () {
"use strict";
const KEY = "character_archive_fixed_v3";
const fields = [
"name", "age", "gender", "height", "job",
"affiliation", "personality", "feature",
"likes", "dislikes", "story", "etc"
];
const outputMap = {
name: "o-name",
age: "o-age",
gender: "o-gender",
height: "o-height",
job: "o-job",
affiliation: "o-affiliation",
personality: "o-personality",
feature: "o-feature",
likes: "o-likes",
dislikes: "o-dislikes",
story: "o-story",
etc: "o-etc"
};
const $ = id => document.getElementById(id);
let characters = [];
let currentId = null;
let currentPhoto = "";
let busy = false;
function say(message) {
$("status").textContent = message;
}
function getForm() {
const values = {};
fields.forEach(id => {
values[id] = $(id).value;
});
return values;
}
function render(values, photo) {
fields.forEach(id => {
const value = (values[id] || "").trim();
$(outputMap[id]).textContent = value || (
id === "name" ? "이름을 입력하세요" : "—"
);
});
$("o-sub").textContent = "CHARACTER PROFILE";
currentPhoto = photo || "";
const img = $("o-photo");
if (currentPhoto) {
img.src = currentPhoto;
img.style.display = "block";
$("placeholder").style.display = "none";
} else {
img.removeAttribute("src");
img.style.display = "none";
$("placeholder").style.display = "flex";
}
}
function updatePreview() {
render(getForm(), currentPhoto);
}
fields.forEach(id => {
$(id).addEventListener("input", updatePreview);
});
function persist() {
try {
localStorage.setItem(KEY, JSON.stringify(characters));
return true;
} catch (error) {
console.error(error);
say(
"저장 실패: 브라우저 저장 공간이 부족하거나 " +
"사이트의 저장 권한이 제한되어 있어요. " +
"사진 용량을 줄이거나 다른 브라우저에서 열어 보세요."
);
return false;
}
}
function load() {
try {
const raw = localStorage.getItem(KEY);
const data = raw ? JSON.parse(raw) : [];
characters = Array.isArray(data) ? data.filter(c =>
c &&
typeof c.id === "string" &&
c.values &&
typeof c.values === "object"
) : [];
} catch (error) {
characters = [];
say("저장된 데이터를 읽지 못했어요. 브라우저 저장 설정을 확인해 주세요.");
}
drawList();
}
function drawList() {
const list = $("list");
list.replaceChildren();
$("count").textContent =
characters.length + " CHARACTERS";
if (!characters.length) {
const empty = document.createElement("div");
empty.className = "empty";
empty.textContent = "저장된 캐릭터가 없습니다.";
list.appendChild(empty);
return;
}
characters.forEach(character => {
const row = document.createElement("div");
row.className = "item";
if (character.id === currentId) {
row.classList.add("active");
}
const open = document.createElement("button");
open.className = "item-open";
open.type = "button";
const thumb = document.createElement("img");
thumb.className = "thumb";
thumb.alt = "";
if (character.photo) {
thumb.src = character.photo;
}
const text = document.createElement("div");
text.style.minWidth = "0";
const name = document.createElement("div");
name.className = "item-name";
name.textContent = character.values.name || "이름 없음";
const info = document.createElement("div");
info.className = "item-info";
info.textContent = [
character.values.age,
character.values.job
].filter(Boolean).join(" · ") || "캐릭터 프로필";
text.append(name, info);
open.append(thumb, text);
open.addEventListener("click", () => {
openCharacter(character.id);
});
const del = document.createElement("button");
del.className = "delete-small";
del.type = "button";
del.textContent = "삭제";
del.addEventListener("click", () => {
deleteCharacter(character.id);
});
row.append(open, del);
list.appendChild(row);
});
}
function openCharacter(id) {
const character = characters.find(c => c.id === id);
if (!character) return;
currentId = character.id;
currentPhoto = character.photo || "";
fields.forEach(id => {
$(id).value = character.values[id] || "";
});
updatePreview();
drawList();
say("캐릭터를 불러왔어요. 수정 후 저장 버튼을 누르세요.");
}
function newCharacter() {
currentId = null;
currentPhoto = "";
fields.forEach(id => {
$(id).value = "";
});
$("photo").value = "";
updatePreview();
drawList();
say("새 캐릭터 작성 중이에요. 기존 캐릭터는 유지됩니다.");
}
$("new").addEventListener("click", newCharacter);
$("save").addEventListener("click", () => {
if (busy) return;
const values = getForm();
if (!values.name.trim()) {
say("저장 실패: 이름을 먼저 입력해 주세요.");
$("name").focus();
return;
}
const previous = characters.map(c => ({
...c,
values: { ...c.values }
}));
const id = currentId || (
Date.now().toString(36) +
Math.random().toString(36).slice(2)
);
const character = {
id,
values,
photo: currentPhoto,
updatedAt: new Date().toISOString()
};
const index = characters.findIndex(c => c.id === id);
if (index >= 0) {
characters[index] = character;
} else {
characters.unshift(character);
}
if (!persist()) {
characters = previous;
drawList();
return;
}
currentId = id;
drawList();
say("저장 완료! 캐릭터가 목록에 등록되었어요.");
});
$("delete").addEventListener("click", () => {
if (!currentId) {
say("먼저 저장된 캐릭터를 불러와 주세요.");
return;
}
deleteCharacter(currentId);
});
function deleteCharacter(id) {
const character = characters.find(c => c.id === id);
if (!character) return;
if (!confirm(
'"' + (character.values.name || "이 캐릭터") +
'"을(를) 삭제할까요?'
)) return;
const previous = characters;
characters = characters.filter(c => c.id !== id);
if (!persist()) {
characters = previous;
drawList();
return;
}
if (currentId === id) {
newCharacter();
} else {
drawList();
}
say("캐릭터를 삭제했어요.");
}
// 업로드한 사진을 작은 JPEG로 변환해 저장 공간 절약
$("photo").addEventListener("change", async event => {
const file = event.target.files[0];
if (!file) return;
if (!file.type.startsWith("image/")) {
say("이미지 파일을 선택해 주세요.");
return;
}
try {
const url = URL.createObjectURL(file);
const img = new Image();
try {
await new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
img.src = url;
});
const max = 800;
const ratio = Math.min(
1,
max / Math.max(img.naturalWidth, img.naturalHeight)
);
const canvas = document.createElement("canvas");
canvas.width = Math.max(1, Math.round(img.naturalWidth * ratio));
canvas.height = Math.max(1, Math.round(img.naturalHeight * ratio));
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
currentPhoto = canvas.toDataURL("image/jpeg", 0.72);
} finally {
URL.revokeObjectURL(url);
}
updatePreview();
say("사진을 불러왔어요. 캐릭터 저장 버튼을 눌러 보존하세요.");
} catch (error) {
console.error(error);
say("사진을 읽지 못했어요. 다른 이미지 파일을 사용해 주세요.");
}
$("photo").value = "";
});
$("removePhoto").addEventListener("click", () => {
currentPhoto = "";
updatePreview();
say("사진을 제거했어요. 변경 사항을 저장해 주세요.");
});
// 텍스트를 캔버스 너비에 맞게 줄바꿈
function wrapText(ctx, text, maxWidth) {
const result = [];
String(text || "—").split("\n").forEach(paragraph => {
if (!paragraph) {
result.push("");
return;
}
let line = "";
for (const char of paragraph) {
const test = line + char;
if (line && ctx.measureText(test).width > maxWidth) {
result.push(line);
line = char;
} else {
line = test;
}
}
result.push(line);
});
return result;
}
// 카드 자체를 캔버스로 그려 PNG 생성
async function makePNG() {
const values = getForm();
if (!values.name.trim()) {
say("이미지를 저장하려면 이름을 먼저 입력해 주세요.");
return;
}
const canvas = document.createElement("canvas");
const scale = 2;
const width = 400;
const padding = 26;
const textWidth = width - padding * 2;
const measure = canvas.getContext("2d");
const sections = [
["PERSONALITY", values.personality],
["FEATURES", values.feature],
["LIKE", values.likes],
["DISLIKE", values.dislikes],
["BACKGROUND", values.story],
["OTHER INFORMATION", values.etc]
];
// 카드 높이 계산
let height = 9 + 280 + 24;
measure.font = "bold 27px Arial, sans-serif";
const nameLines = wrapText(
measure,
values.name,
textWidth
);
height += 12 + 12 + nameLines.length * 36 + 26;
height += 20 + 1 + 20;
const infoRows = [
[
["AGE", values.age],
["GENDER", values.gender]
],
[
["HEIGHT", values.height],
["OCCUPATION", values.job]
],
[
["AFFILIATION", values.affiliation]
]
];
infoRows.forEach(row => {
let maxLines = 1;
row.forEach((field, index) => {
measure.font = "12px Arial, sans-serif";
const lines = wrapText(
measure,
field[1] || "—",
row.length === 1 ? textWidth : textWidth / 2 - 8
);
maxLines = Math.max(maxLines, lines.length);
});
height += maxLines * 20 + 28;
});
height += 10;
sections.forEach(section => {
if (!section[1].trim()) return;
measure.font = "12px Arial, sans-serif";
const lines = wrapText(
measure,
section[1],
textWidth
);
height += 23 + lines.length * 21 + 20;
});
height += 55;
canvas.width = width * scale;
canvas.height = Math.ceil(height) * scale;
const ctx = canvas.getContext("2d");
ctx.scale(scale, scale);
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, width, height);
let y = 0;
// 상단 띠
ctx.fillStyle = "#292929";
ctx.fillRect(0, y, width, 9);
y += 9;
// 사진 영역
ctx.fillStyle = "#eeeeee";
ctx.fillRect(0, y, width, 280);
if (currentPhoto) {
const img = new Image();
await new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
img.src = currentPhoto;
});
const ratio = Math.max(
width / img.naturalWidth,
280 / img.naturalHeight
);
const w = img.naturalWidth * ratio;
const h = img.naturalHeight * ratio;
ctx.save();
ctx.beginPath();
ctx.rect(0, y, width, 280);
ctx.clip();
ctx.drawImage(
img,
(width - w) / 2,
y + (280 - h) / 2,
w,
h
);
ctx.restore();
} else {
ctx.fillStyle = "#999";
ctx.font = "12px Arial, sans-serif";
ctx.textAlign = "center";
ctx.fillText("CHARACTER IMAGE", width / 2, y + 145);
ctx.textAlign = "left";
}
y += 304;
// 이름
ctx.fillStyle = "#999";
ctx.font = "10px Arial, sans-serif";
ctx.fillText("CHARACTER FILE", padding, y);
y += 28;
ctx.fillStyle = "#292929";
ctx.font = "bold 27px Arial, sans-serif";
nameLines.forEach(line => {
ctx.fillText(line, padding, y);
y += 36;
});
ctx.fillStyle = "#888";
ctx.font = "11px Arial, sans-serif";
ctx.fillText("CHARACTER PROFILE", padding, y);
y += 27;
// 구분선
ctx.strokeStyle = "#e5e5e5";
ctx.beginPath();
ctx.moveTo(padding, y);
ctx.lineTo(width - padding, y);
ctx.stroke();
y += 20;
// 기본 정보
infoRows.forEach(row => {
const columnWidth = row.length === 1
? textWidth
: textWidth / 2 - 8;
let maxLines = 1;
const prepared = row.map(field => {
ctx.font = "12px Arial, sans-serif";
const lines = wrapText(
ctx,
field[1] || "—",
columnWidth
);
maxLines = Math.max(maxLines, lines.length);
return { field, lines };
});
prepared.forEach((item, index) => {
const x = padding + index * (textWidth / 2 + 8);
ctx.fillStyle = "#999";
ctx.font = "9px Arial, sans-serif";
ctx.fillText(item.field[0], x, y);
ctx.fillStyle = "#333";
ctx.font = "12px Arial, sans-serif";
item.lines.forEach((line, lineIndex) => {
ctx.fillText(line, x, y + 20 + lineIndex * 20);
});
});
y += maxLines * 20 + 28;
});
y += 5;
// 상세 설정
sections.forEach(section => {
if (!section[1].trim()) return;
ctx.fillStyle = "#888";
ctx.font = "10px Arial, sans-serif";
ctx.fillText(section[0], padding, y);
y += 22;
ctx.fillStyle = "#444";
ctx.font = "12px Arial, sans-serif";
const lines = wrapText(
ctx,
section[1],
textWidth
);
lines.forEach(line => {
ctx.fillText(line, padding, y);
y += 21;
});
y += 20;
});
// 하단
ctx.strokeStyle = "#eee";
ctx.beginPath();
ctx.moveTo(padding, y);
ctx.lineTo(width - padding, y);
ctx.stroke();
y += 24;
ctx.fillStyle = "#aaa";
ctx.font = "8px Arial, sans-serif";
ctx.fillText("CHARACTER ARCHIVE", padding, y);
ctx.textAlign = "right";
ctx.fillText("CONFIDENTIAL", width - padding, y);
return canvas;
}
$("png").addEventListener("click", async () => {
if (busy) return;
busy = true;
$("png").disabled = true;
$("png").textContent = "이미지 생성 중...";
try {
const canvas = await makePNG();
const blob = await new Promise(resolve => {
canvas.toBlob(resolve, "image/png");
});
if (!blob) {
throw new Error("PNG 생성 실패");
}
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download =
(getForm().name.trim() || "character")
.replace(/[\\/:*?"<>|]/g, "_") +
"_profile.png";
document.body.appendChild(link);
link.click();
link.remove();
setTimeout(() => URL.revokeObjectURL(url), 30000);
say("PNG 이미지 생성 완료! 다운로드 폴더를 확인해 주세요.");
} catch (error) {
console.error(error);
say(
"이미지 생성 실패: " +
(error.message || "다시 시도해 주세요.")
);
} finally {
busy = false;
$("png").disabled = false;
$("png").textContent = "↓ PNG 이미지 저장";
}
});
// 시작
load();
newCharacter();
})();
</script>
</body>
</html>