feat: complete ANL lab web application with lossless data migration and SSG routes

This commit is contained in:
2026-07-30 10:34:22 +09:00
parent 293431c1e8
commit ea26ef503e
23 changed files with 5326 additions and 882 deletions
@@ -0,0 +1,87 @@
import React from "react";
export function DirectionsBlock() {
return (
<section className="mt-20 pt-16 border-t border-line" id="directions">
<div className="flex items-center gap-3 mb-6">
<span className="h-px w-8 bg-vermillion"></span>
<span className="font-mono text-xs tracking-widest uppercase text-vermillion font-bold">
Location & Contact
</span>
</div>
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8">
{/* Left info column */}
<div className="lg:col-span-7 space-y-6">
<h2 className="font-serif text-3xl font-normal text-ink">
&
</h2>
<p className="text-ink-mute text-base leading-relaxed">
AI (ANL) IT대학 5 , .
</p>
<address className="not-italic space-y-4 pt-2 text-sm font-sans text-ink">
<div className="flex items-start gap-3">
<span className="font-mono text-xs uppercase tracking-wider text-ink-mute w-20 pt-0.5">
</span>
<div>
<p className="font-medium">
IT대학 5(415) 527
</p>
<p className="text-xs text-ink-mute mt-0.5">
School of Computer Science and Engineering, Kyungpook National University
</p>
</div>
</div>
<div className="flex items-center gap-3">
<span className="font-mono text-xs uppercase tracking-wider text-ink-mute w-20">
</span>
<span>
(<a href="mailto:sjkoh@knu.ac.kr" className="text-vermillion hover:underline">sjkoh@knu.ac.kr</a>)
</span>
</div>
<div className="flex items-start gap-3">
<span className="font-mono text-xs uppercase tracking-wider text-ink-mute w-20 pt-0.5">
</span>
<div className="flex flex-wrap gap-x-4 gap-y-1 text-xs font-mono text-cobalt">
<a href="http://www.knu.ac.kr/" target="_blank" rel="noreferrer" className="hover:underline">
(KNU)
</a>
<a href="http://cse.knu.ac.kr/" target="_blank" rel="noreferrer" className="hover:underline">
</a>
<a href="http://it.knu.ac.kr/" target="_blank" rel="noreferrer" className="hover:underline">
IT대학
</a>
</div>
</div>
</address>
</div>
{/* Right card column */}
<div className="lg:col-span-5 bg-paper p-6 rounded-lg border border-line flex flex-col justify-between">
<div className="space-y-4">
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider">
Research Environment
</div>
<h3 className="font-serif text-xl font-normal text-ink">
AI Agent Networking Lab
</h3>
<p className="text-xs text-ink-mute leading-relaxed">
QUIC/gRPC .
</p>
</div>
<div className="mt-6 pt-4 border-t border-line flex justify-between items-center text-xs font-mono text-ink-mute">
<span>IT-5 Building #527</span>
<span className="text-vermillion font-bold">ANL Laboratory</span>
</div>
</div>
</div>
</section>
);
}
-313
View File
@@ -1,313 +0,0 @@
import type { Metadata } from "next";
import Link from "next/link";
import Reveal from "@/components/Reveal";
import Marquee from "@/components/Marquee";
import Counter from "@/components/Counter";
import SectionLabel from "@/components/SectionLabel";
import HeroComposition from "./_components/HeroComposition";
export const metadata: Metadata = {
title: "연구실 소개 (Intro)",
description:
"QUIC, gRPC, A2A 기반 에이전트 통신 및 멀티에이전트 오케스트레이션을 연구하는 경북대학교 AI 에이전트 네트워크 연구실 (ANL) 소개.",
};
// CUSTOMIZATION HOOK: the five research pillars (5 Pillars, Option A).
const pillars = [
{
no: "Pillar 01",
tag: "Agent Eng",
accent: "vermillion" as const,
ko: "AI 에이전트 3대 핵심 엔지니어링",
en: "Agent Core Engineering",
desc: "프롬프트, 컨텍스트, 하네스 엔지니어링을 결합하여 대화 상태 보존, 외부 기억 바인딩, 도구 연동 인터페이스를 설계하고 자율 추론 경로를 최적화합니다.",
points: [
"역할 페르소나 및 Few-shot 최적화",
"동적 컨텍스트 윈도우 & Memory 바인딩",
"물리적 도구(Tool Use) 하네스 연결",
],
},
{
no: "Pillar 02",
tag: "MCP & SKILL",
accent: "cobalt" as const,
ko: "AI Agent 기능 확장 프로토콜",
en: "Extensibility & Protocol",
desc: "Anthropic MCP 통일 호환 규격 및 코드+스키마+Few-shot이 패키징된 SKILL 모듈을 통해 에이전트의 로컬/원격 역량을 자율적으로 동적 확장합니다.",
points: [
"MCP (Model Context Protocol) 통일 규격",
"자율 확장 SKILL 모듈 패키징",
"CLI 기반 자율 코딩 에이전트 제어",
],
},
{
no: "Pillar 03",
tag: "Orchestration",
accent: "vermillion" as const,
ko: "멀티 에이전트 협업 및 오케스트레이션",
en: "Multi-Agent Systems",
desc: "단일 에이전트의 환각과 컨텍스트 인지 한계를 극복하기 위해 역할 세분화(Role Specialization) 및 이종 모델 교차 검증과 오케스트레이션 인프라를 구축합니다.",
points: [
"HERDR 백그라운드 프로세스 컨테이너 격리",
"crewAI 역할/목표 기반 크루 프로세스",
"LangGraph 상태 보존형 순환 그래프 제어",
],
},
{
no: "Pillar 04",
tag: "A2A & ACP",
accent: "cobalt" as const,
ko: "에이전트 상호운용성 개방형 표준",
en: "Interoperability Standards",
desc: "Linux Foundation A2A 및 IBM ACP 오픈 표준 기반으로 이종 에이전트 간 서비스 발견, 태스크 위임, Agent Card 프로필 명세를 구현합니다.",
points: [
"A2A (Agent-to-Agent) 통신 오픈 표준",
"ACP 서비스 발견 & 태스크 위임",
"Agent Card (/.well-known/agent-card.json)",
],
},
{
no: "Pillar 05",
tag: "AIoT & gRPC",
accent: "vermillion" as const,
ko: "AIoT & 고성능 통신 백본",
en: "High-Performance Backbone",
desc: "스마트 팩토리/팜 엣지 자원 제약 환경에서 경량 프로토콜(MQTT/CoAP)과 HTTP/2·HTTP/3 gRPC/QUIC 양방향 스트리밍을 결합한 하이브리드 백본을 설계합니다.",
points: [
"gRPC & QUIC 양방향 스트리밍 메시징",
"Protobuf 바이너리 직렬화 최적화",
"MQTT-gRPC 하이브리드 엣지 메쉬",
],
},
];
// CUSTOMIZATION HOOK: headline figures (animated counters).
// `value: 2026` is marked static so it renders as a fixed year, not a
// 0→2026 count-up, at the smaller `display-sm` scale so the 4-digit year
// does not push the cell padding. See LAYOUT_AUDIT #11 + #13.
const figures = [
{ value: pillars.length, label: "연구 기둥 · Research Pillars", suffix: "", size: "display" as const, static: false },
{ value: pillars.reduce((n, p) => n + p.points.length, 0), label: "세부 연구 주제 · Research Topics", suffix: "", size: "display" as const, static: false },
{ value: 2026, label: "Issue · 발행", suffix: "", size: "display-sm" as const, static: true },
];
// CUSTOMIZATION HOOK: research keyword ticker.
const keywords = [
"A2A PROTOCOL",
"MCP & SKILL",
"HERDR PROCESS CONTAINER",
"LANGGRAPH CYCLIC GRAPH",
"QUIC & GRPC STREAMING",
"MULTI-AGENT ORCHESTRATION",
"AIOT EDGE CONTROL",
"AGENT CARD SPEC",
];
const focusAreas = [
{ ko: "에이전트 통신 프로토콜 (A2A)", en: "A2A & ACP Protocols" },
{ ko: "멀티에이전트 오케스트레이션", en: "Multi-Agent Orchestration" },
{ ko: "MCP & SKILL 기능 확장", en: "MCP & SKILL Engineering" },
{ ko: "AIoT & gRPC/QUIC 백본", en: "AIoT & gRPC/QUIC Backbone" },
];
export default function IntroPage() {
return (
<>
{/* ============ COVER SPREAD ============ */}
<section className="relative overflow-hidden border-b border-ink">
<div className="container-content pb-10 pt-12 sm:pt-16">
<Reveal>
<SectionLabel index={1} label="The Cover" />
</Reveal>
<div className="mt-8 grid items-start gap-10 lg:grid-cols-12">
{/* Title & Masthead column */}
<div className="lg:col-span-7">
<Reveal delay={100}>
<p className="kicker"> · AI Agent Networking Lab (ANL)</p>
<h1 className="headline-ko mt-4 text-[clamp(2.5rem,8vw,5.5rem)] leading-[0.98] text-ink">
<br />
<span className="text-vermillion"></span>
</h1>
<p className="display mt-3 leading-[0.9]" aria-hidden>
Agents
<span className="block italic text-cobalt">in&nbsp;Motion</span>
</p>
</Reveal>
<Reveal delay={200}>
<p className="mt-8 max-w-prose text-base leading-relaxed text-ink-soft">
A2A·ACP HERDR·LangGraph
.
.
</p>
</Reveal>
<Reveal delay={260}>
<div className="mt-8 flex flex-wrap gap-3">
<Link
href="/publications"
className="bg-ink px-6 py-3 text-sm font-semibold uppercase tracking-[0.16em] text-ivory transition hover:bg-vermillion"
>
</Link>
<Link
href="/members"
className="border border-ink px-6 py-3 text-sm font-semibold uppercase tracking-[0.16em] text-ink transition hover:bg-ink hover:text-ivory"
>
</Link>
</div>
</Reveal>
</div>
{/* Abstract illustration column */}
<Reveal variant="scale" delay={200} className="lg:col-span-5">
<HeroComposition className="w-full" />
<p className="mt-3 text-right text-xs italic text-ink-mute">
Fig. 01 A2A × QUIC/gRPC
</p>
</Reveal>
</div>
</div>
{/* Keyword marquee band */}
<Reveal>
<Marquee
items={keywords}
className="border-y border-ink bg-ink py-3 font-display text-xl tracking-wide text-ivory"
/>
</Reveal>
</section>
{/* ============ FIGURES / COUNTERS ============ */}
<section className="border-b border-ink">
<div className="container-content grid gap-px bg-line sm:grid-cols-3">
{figures.map((f, i) => (
<Reveal key={f.label} delay={i * 100} className="bg-ivory">
<div className="px-6 py-10">
<Counter
value={f.value}
suffix={f.suffix}
static={f.static}
className={`${f.size} block text-ink`}
/>
<p className="kicker mt-3">{f.label}</p>
</div>
</Reveal>
))}
</div>
</section>
{/* ============ MISSION / PULL QUOTE ============ */}
<section className="border-b border-ink">
<div className="container-content py-16 sm:py-24">
<Reveal>
<SectionLabel index={2} label="Mission" />
</Reveal>
<Reveal delay={100}>
<blockquote className="pull-quote mt-10 max-w-4xl text-ink">
, {" "}
<span className="text-vermillion"> </span>{" "}
<span className="text-cobalt"> </span> .
</blockquote>
</Reveal>
<Reveal delay={160}>
<p className="mt-6 max-w-prose text-sm leading-relaxed text-ink-mute">
{/* CUSTOMIZATION HOOK: marginalia / footnote */}
(A2A/ACP) (HERDR/LangGraph) , ·
.
</p>
</Reveal>
</div>
</section>
{/* ============ FIVE RESEARCH PILLARS ============ */}
<section className="border-b border-ink">
<div className="container-content py-16 sm:py-24">
<Reveal>
<SectionLabel index={3} label="Five Research Pillars" />
</Reveal>
<div className="mt-12 grid gap-px bg-line sm:grid-cols-2 lg:grid-cols-6">
{pillars.map((p, i) => {
const isVerm = p.accent === "vermillion";
const span = `${i < 3 ? "lg:col-span-2" : "lg:col-span-3"}${i === 4 ? " sm:col-span-2" : ""}`;
return (
<Reveal
key={p.tag}
variant={i % 2 === 0 ? "left" : "right"}
delay={i * 80}
className={`bg-ivory ${span}`}
>
<article
className={`group flex h-full flex-col justify-between border border-ink p-8 transition-colors duration-500 sm:p-10 ${
isVerm
? "hover:bg-vermillion hover:text-ivory"
: "hover:bg-cobalt hover:text-ivory"
}`}
>
<div>
<div className="flex items-baseline justify-between">
<span className="kicker group-hover:text-ivory/70">{p.no}</span>
<span
className={`font-display text-2xl ${
isVerm ? "text-vermillion" : "text-cobalt"
} group-hover:text-ivory`}
>
{p.tag}
</span>
</div>
<h3 className="headline-ko mt-6 text-2xl leading-tight">
{p.ko}
</h3>
<p className="font-display mt-1 text-base italic opacity-70">
{p.en}
</p>
<p className="mt-5 text-sm leading-relaxed opacity-90">
{p.desc}
</p>
</div>
<ul className="mt-6 space-y-3 text-sm">
{p.points.map((pt) => (
<li key={pt} className="flex gap-3 border-t border-ink/20 pt-3 group-hover:border-ivory/20">
<span className="font-display text-xs opacity-60"></span>
<span>{pt}</span>
</li>
))}
</ul>
</article>
</Reveal>
);
})}
</div>
</div>
</section>
{/* ============ FOCUS AREAS ============ */}
<section>
<div className="container-content py-16 sm:py-24">
<Reveal>
<SectionLabel index={4} label="Focus Areas" />
</Reveal>
<div className="mt-10 grid gap-px bg-line sm:grid-cols-2 lg:grid-cols-4">
{focusAreas.map((f, i) => (
<Reveal key={f.en} delay={i * 80} className="bg-ivory">
<div className="group flex h-full flex-col justify-between gap-8 p-7 transition-colors duration-500 hover:bg-ink hover:text-ivory">
<span className="font-display text-2xl text-ink-mute group-hover:text-vermillion">
{String(i + 1).padStart(2, "0")}
</span>
<div>
<p className="headline-ko text-lg">{f.ko}</p>
<p className="mt-1 text-xs uppercase tracking-[0.16em] text-ink-mute group-hover:text-ivory/60">
{f.en}
</p>
</div>
</div>
</Reveal>
))}
</div>
</div>
</section>
</>
);
}
+120 -93
View File
@@ -1,102 +1,129 @@
import type { Metadata } from "next";
import PageHeader from "@/components/PageHeader";
import Reveal from "@/components/Reveal";
import SectionLabel from "@/components/SectionLabel";
export const metadata: Metadata = {
title: "강의 (Lectures)",
description: "AI 에이전트 네트워크 연구실 (ANL) 지도교수가 담당하는 강의 목록 (placeholder).",
};
// CUSTOMIZATION HOOK: replace placeholder lectures below.
const lectures = [
{
code: "CSE3xx",
ko: "사물인터넷 개론",
en: "Introduction to IoT",
level: "학부 · Undergraduate",
accent: "vermillion" as const,
desc: "IoT 아키텍처, 센서·액추에이터, 통신 프로토콜(MQTT/CoAP)과 oneM2M 표준의 기본 개념을 다룹니다. 간단한 디바이스–서버 연동 실습을 포함합니다.",
},
{
code: "CSE4xx",
ko: "네트워크 프로토콜과 전송 기술",
en: "Network Protocols & Transport",
level: "학부/대학원 · Undergraduate / Graduate",
accent: "cobalt" as const,
desc: "TCP/UDP에서 QUIC까지 전송 계층의 발전과 설계 원리를 학습합니다. 스트림 다중화, 연결 마이그레이션, 혼잡 제어를 실험을 통해 분석합니다.",
},
{
code: "CSE6xx",
ko: "메타버스 상호운용성과 표준",
en: "Metaverse Interoperability & Standards",
level: "대학원 · Graduate",
accent: "ink" as const,
desc: "이종 메타버스 플랫폼 간 데이터 모델, 의미 보존 변환, W3C/oneM2M 표준을 다루는 세미나형 대학원 강의입니다. 최신 논문 리뷰와 프로젝트를 병행합니다.",
},
];
const accent: Record<string, { hover: string; text: string }> = {
vermillion: { hover: "hover:bg-vermillion hover:text-ivory", text: "text-vermillion" },
cobalt: { hover: "hover:bg-cobalt hover:text-ivory", text: "text-cobalt" },
ink: { hover: "hover:bg-ink hover:text-ivory", text: "text-ink" },
};
import React from "react";
import { semesters } from "../../content/lectures";
export default function LecturesPage() {
const recentSemesters = semesters.slice(0, 3);
const olderSemesters = semesters.slice(3);
return (
<>
<PageHeader
ko="강의"
en="Lectures"
index={4}
description="연구실에서 담당하는 학부·대학원 강의입니다. 아래 강의 정보는 예시(placeholder)이며 실제 개설 과목으로 교체할 수 있습니다."
/>
<div className="space-y-16 py-6">
{/* Header */}
<section className="space-y-3">
<div className="flex items-center gap-3">
<span className="h-px w-8 bg-vermillion"></span>
<span className="font-mono text-xs tracking-widest uppercase text-vermillion font-bold">
Academic Courses
</span>
</div>
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink">
</h1>
<p className="text-ink-mute text-base max-w-2xl">
2016 2026 20 / .
</p>
</section>
<section>
<div className="container-content py-16 sm:py-24">
<Reveal>
<SectionLabel index={1} label="Courses" />
</Reveal>
<div className="mt-12 grid gap-px bg-line lg:grid-cols-3">
{lectures.map((l, i) => {
const a = accent[l.accent];
return (
<Reveal
key={l.code}
variant={i === 0 ? "left" : i === 2 ? "right" : "up"}
delay={i * 100}
className="bg-ivory"
>
<article
className={`group flex h-full flex-col border border-ink p-8 transition-colors duration-500 sm:p-10 ${a.hover}`}
>
<div className="flex items-baseline justify-between">
<span className={`font-display text-xl ${a.text} group-hover:text-ivory`}>
{l.code}
</span>
<span className="font-display text-4xl text-ink-mute group-hover:text-ivory/70">
{String(i + 1).padStart(2, "0")}
</span>
</div>
<h3 className="headline-ko mt-6 text-2xl leading-tight">{l.ko}</h3>
<p className="font-display mt-1 text-lg italic opacity-70">{l.en}</p>
<p className={`mt-4 inline-flex w-fit border border-ink/30 px-3 py-1 text-xs font-semibold uppercase tracking-[0.16em] group-hover:border-ivory/40`}>
{l.level}
</p>
<p className="mt-6 border-t border-ink/20 pt-6 text-sm leading-relaxed opacity-90 group-hover:border-ivory/20">
{l.desc}
</p>
</article>
</Reveal>
);
})}
{/* Recent 3 Semesters */}
<section className="space-y-6 pt-6 border-t border-line">
<div className="flex justify-between items-end">
<div>
<div className="font-mono text-xs text-vermillion uppercase tracking-widest font-bold">
Recent Courses ({recentSemesters.length} Semesters)
</div>
<h2 className="font-serif text-3xl font-normal text-ink mt-1">
</h2>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{recentSemesters.map((sem, idx) => (
<div
key={idx}
className="bg-paper p-6 rounded-lg border border-line space-y-4 flex flex-col justify-between"
>
<div className="space-y-3">
<div className="flex justify-between items-center border-b border-line pb-2">
<span className="font-serif text-xl font-normal text-ink">
{sem.term} {sem.year}
</span>
<span className="font-mono text-xs text-vermillion font-bold">
Latest
</span>
</div>
<ul className="space-y-2 pt-1">
{sem.courses.map((c, cIdx) => (
<li key={cIdx} className="space-y-0.5">
<div className="font-serif text-base text-ink">
{c.en}
</div>
<div className="font-mono text-xs text-ink-mute">
Code: {c.code} {c.note && `(${c.note})`}
</div>
</li>
))}
</ul>
</div>
<div className="pt-3 border-t border-line/60 font-mono text-xs text-ink-mute">
Course Count: {sem.courses.length}
</div>
</div>
))}
</div>
</section>
</>
{/* Older Semesters (Native <details>/<summary> progressive disclosure) */}
<section className="space-y-6 pt-6 border-t border-line">
<details className="group border border-line rounded-lg bg-paper p-6 transition-all duration-200">
<summary className="flex justify-between items-center cursor-pointer list-none select-none">
<div className="space-y-1">
<span className="font-serif text-xl font-normal text-ink">
({olderSemesters.length} )
</span>
<p className="text-xs text-ink-mute font-mono">
2016 Fall ~ 2024 Spring
</p>
</div>
<span className="font-mono text-xs text-vermillion font-bold border border-vermillion px-3 py-1.5 rounded group-open:bg-vermillion group-open:text-ivory transition-colors">
<span className="group-open:hidden"> </span>
<span className="hidden group-open:inline"> </span>
</span>
</summary>
<div className="mt-6 pt-6 border-t border-line grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{olderSemesters.map((sem, idx) => (
<div
key={idx}
className="bg-ivory p-5 rounded border border-line space-y-3"
>
<div className="font-serif text-lg font-normal text-ink border-b border-line pb-1.5 flex justify-between">
<span>
{sem.term} {sem.year}
</span>
<span className="font-mono text-xs text-ink-mute">
{sem.courses.length} Courses
</span>
</div>
<ul className="space-y-2">
{sem.courses.map((c, cIdx) => (
<li key={cIdx} className="space-y-0.5">
<div className="font-serif text-sm text-ink">
{c.en}
</div>
<div className="font-mono text-[0.7rem] text-ink-mute">
Code: {c.code} {c.note && `(${c.note})`}
</div>
</li>
))}
</ul>
</div>
))}
</div>
</details>
</section>
</div>
);
}
+194 -155
View File
@@ -1,174 +1,213 @@
import type { Metadata } from "next";
import PageHeader from "@/components/PageHeader";
import Reveal from "@/components/Reveal";
import SectionLabel from "@/components/SectionLabel";
import Counter from "@/components/Counter";
export const metadata: Metadata = {
title: "구성원 (Members)",
description: "AI 에이전트 네트워크 연구실 (ANL) 지도교수 및 대학원·학부 연구원 소개 (placeholder).",
};
// CUSTOMIZATION HOOK: replace placeholder member data below.
const advisor = {
ko: "고석주 교수",
en: "Prof. Seok-Joo Koh",
role: "지도교수 · Principal Investigator",
desc: "QUIC/gRPC/A2A 에이전트 통신, 멀티에이전트 오케스트레이션, MCP & SKILL 확장, 네트워크 프로토콜. (sjkoh@knu.ac.kr)",
fields: ["Agent Communication (A2A)", "Multi-Agent Orchestration", "QUIC & gRPC Transport"],
};
const groups = [
{
ko: "박사과정 연구원",
en: "Ph.D. Students",
accent: "vermillion" as const,
members: [
{ name: "연구원 A (placeholder)", topic: "QUIC 기반 멀티에이전트 오케스트레이션" },
{ name: "연구원 B (placeholder)", topic: "메타버스 공통 정보 모델 (MCM)" },
],
},
{
ko: "석사과정 연구원",
en: "M.S. Students",
accent: "cobalt" as const,
members: [
{ name: "연구원 C (placeholder)", topic: "oneM2M 적합성 검증" },
{ name: "연구원 D (placeholder)", topic: "QUIC 스트림 다중화 성능 분석" },
{ name: "연구원 E (placeholder)", topic: "W3C WoT Thing Description 매핑" },
],
},
{
ko: "학부 연구원",
en: "Undergraduate Researchers",
accent: "ink" as const,
members: [
{ name: "연구원 F (placeholder)", topic: "테스트베드 개발" },
{ name: "연구원 G (placeholder)", topic: "데이터 시각화" },
],
},
];
// CUSTOMIZATION HOOK: headcount figures (animated counters).
const figures = [
{ value: 1, label: "지도교수 · Principal Investigator" },
{ value: 5, label: "대학원 연구원 · Graduate Members" },
{ value: 2, label: "학부 연구원 · Undergraduates" },
];
const accentText: Record<string, string> = {
vermillion: "text-vermillion",
cobalt: "text-cobalt",
ink: "text-ink",
};
import React from "react";
import { activeMembers, alumni } from "../../content/members";
export default function MembersPage() {
return (
<>
<PageHeader
ko="구성원"
en="Members"
index={2}
description="연구실 지도교수와 박사·석사·학부 연구원을 소개합니다. 아래 정보는 예시(placeholder)이며 실제 구성원 정보로 교체할 수 있습니다."
/>
const professor = activeMembers.find((m) => m.degree === "Professor");
const phdStudents = activeMembers.filter(
(m) => m.degree === "PhD" || m.degree === "PhDCandidate" || m.degree === "PhDStudent"
);
const msStudents = activeMembers.filter(
(m) => m.degree === "MSCandidate" || m.degree === "MSStudent"
);
{/* ============ HEADCOUNT FIGURES ============ */}
<section className="border-b border-ink">
<div className="container-content grid gap-px bg-line sm:grid-cols-3">
{figures.map((f, i) => (
<Reveal key={f.label} delay={i * 100} className="bg-ivory">
<div className="px-6 py-10">
<Counter value={f.value} className="display block text-ink" />
<p className="kicker mt-3">{f.label}</p>
</div>
</Reveal>
))}
return (
<div className="space-y-16 py-6">
{/* Header */}
<section className="space-y-3">
<div className="flex items-center gap-3">
<span className="h-px w-8 bg-vermillion"></span>
<span className="font-mono text-xs tracking-widest uppercase text-vermillion font-bold">
People & Researchers
</span>
</div>
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink">
</h1>
<p className="text-ink-mute text-base max-w-2xl">
16, IT 60 .
</p>
</section>
{/* ============ PRINCIPAL INVESTIGATOR ============ */}
<section className="border-b border-ink">
<div className="container-content py-16 sm:py-24">
<Reveal>
<SectionLabel index={1} label="Principal Investigator" />
</Reveal>
{/* Professor Section */}
<section className="space-y-6 pt-6 border-t border-line">
<div className="font-mono text-xs text-vermillion uppercase tracking-widest font-bold">
Faculty
</div>
<div className="mt-10 grid gap-px lg:grid-cols-12">
<Reveal variant="left" className="lg:col-span-7">
<article className="group h-full border border-ink p-8 transition-colors duration-500 hover:bg-ink hover:text-ivory sm:p-10">
<span className="kicker group-hover:text-ivory/70">{advisor.role}</span>
<h2 className="headline-ko mt-5 text-4xl leading-tight">{advisor.ko}</h2>
<p className="font-display mt-1 text-2xl italic text-vermillion">
{advisor.en}
</p>
<p className="mt-6 max-w-prose text-sm leading-relaxed opacity-90">
{advisor.desc}
</p>
</article>
</Reveal>
<Reveal variant="right" delay={120} className="lg:col-span-5">
<div className="flex h-full flex-col gap-px bg-line">
{advisor.fields.map((field, i) => (
<div
key={field}
className="group flex items-center gap-5 bg-ivory px-7 py-6 transition-colors duration-500 hover:bg-paper"
>
<span className="font-display text-3xl text-ink-mute group-hover:text-vermillion">
{String(i + 1).padStart(2, "0")}
</span>
<span className="text-sm uppercase tracking-[0.16em] text-ink-soft">
{field}
</span>
</div>
))}
</div>
</Reveal>
<div className="bg-paper p-8 rounded-lg border border-line grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
<div className="lg:col-span-8 space-y-4">
<div className="flex items-baseline gap-3">
<h2 className="font-serif text-3xl font-normal text-ink">
{professor?.ko || "고석주"}
</h2>
<span className="font-mono text-sm text-ink-mute">
{professor?.en || "Seok-Joo Koh"}, Professor
</span>
</div>
<p className="text-sm text-ink-mute leading-relaxed">
· AI (ANL) .
QUIC/gRPC , A2A/ACP , MCP &amp; SKILL .
</p>
<div className="pt-4 border-t border-line/60 flex flex-wrap gap-4 text-xs font-mono">
<a
href="mailto:sjkoh@knu.ac.kr"
className="text-vermillion hover:underline"
>
sjkoh@knu.ac.kr
</a>
<span className="text-ink-mute"></span>
<a
href="https://github.com/sjkoh12"
target="_blank"
rel="noreferrer"
className="text-cobalt hover:underline"
>
GitHub @sjkoh12
</a>
</div>
</div>
<div className="lg:col-span-4 bg-ivory p-6 rounded border border-line text-xs space-y-2 font-mono">
<div className="text-ink font-bold border-b border-line pb-1">
Affiliation & Office
</div>
<p className="text-ink-mute">Kyungpook National University</p>
<p className="text-ink-mute">IT Building #5 Room 527</p>
<p className="text-ink-mute">Daegu, Republic of Korea</p>
</div>
</div>
</section>
{/* ============ RESEARCH GROUPS ============ */}
<section>
<div className="container-content py-16 sm:py-24">
<Reveal>
<SectionLabel index={2} label="Researchers" />
</Reveal>
{/* Active Researchers Section */}
<section className="space-y-8 pt-6 border-t border-line">
<div className="flex justify-between items-end">
<div>
<div className="font-mono text-xs text-cobalt uppercase tracking-widest font-bold">
Active Researchers ({activeMembers.length} Members)
</div>
<h2 className="font-serif text-3xl font-normal text-ink mt-1">
</h2>
</div>
</div>
{groups.map((g, gi) => (
<div key={g.en} className="mt-14 first:mt-12">
<Reveal>
<div className="flex items-baseline justify-between border-b border-ink pb-4">
<h3 className="headline-ko text-2xl text-ink sm:text-3xl">{g.ko}</h3>
<span
className={`font-display text-lg italic ${accentText[g.accent]}`}
>
{g.en}
{/* Ph.D. Candidates / Students */}
<div className="space-y-4">
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
Ph.D. Course ({phdStudents.length})
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{phdStudents.map((mem, idx) => (
<div
key={idx}
className="bg-paper p-5 rounded border border-line space-y-2 hover:border-cobalt transition-colors"
>
<div className="flex justify-between items-baseline">
<span className="font-serif text-lg font-normal text-ink">
{mem.ko}
</span>
<span className="font-mono text-xs text-cobalt">
{mem.degree}
</span>
</div>
</Reveal>
<div className="mt-px grid gap-px bg-line sm:grid-cols-2">
{g.members.map((m, mi) => (
<Reveal key={m.name} delay={mi * 80} className="bg-ivory">
<article className="group flex h-full flex-col justify-between gap-8 p-7 transition-colors duration-500 hover:bg-ink hover:text-ivory">
<span className="font-display text-2xl text-ink-mute group-hover:text-vermillion">
{String(gi + 1).padStart(2, "0")}.{String(mi + 1).padStart(2, "0")}
</span>
<div>
<h4 className="headline-ko text-lg">{m.name}</h4>
<p className="mt-2 text-xs leading-relaxed text-ink-mute group-hover:text-ivory/60">
{m.topic}
</p>
</div>
</article>
</Reveal>
))}
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
{mem.affiliation && (
<div className="text-xs text-vermillion pt-1 border-t border-line/40">
with {mem.affiliation}
</div>
)}
</div>
</div>
))}
))}
</div>
</div>
{/* M.S. Candidates / Students */}
<div className="space-y-4 pt-4">
<h3 className="font-mono text-xs uppercase tracking-wider text-ink-mute border-b border-line pb-2">
M.S. Course ({msStudents.length})
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{msStudents.map((mem, idx) => (
<div
key={idx}
className="bg-paper p-5 rounded border border-line space-y-2 hover:border-cobalt transition-colors"
>
<div className="flex justify-between items-baseline">
<span className="font-serif text-lg font-normal text-ink">
{mem.ko}
</span>
<span className="font-mono text-xs text-cobalt">
{mem.degree}
</span>
</div>
<div className="font-mono text-xs text-ink-mute">{mem.en}</div>
{mem.affiliation && (
<div className="text-xs text-vermillion pt-1 border-t border-line/40">
with {mem.affiliation}
</div>
)}
</div>
))}
</div>
</div>
</section>
</>
{/* Alumni Section (Native <details>/<summary> progressive disclosure) */}
<section className="space-y-6 pt-6 border-t border-line">
<div className="flex justify-between items-end">
<div>
<div className="font-mono text-xs text-ink-mute uppercase tracking-widest font-bold">
Alumni Inventory ({alumni.length} Graduates)
</div>
<h2 className="font-serif text-3xl font-normal text-ink mt-1">
</h2>
</div>
</div>
<details className="group border border-line rounded-lg bg-paper p-6 transition-all duration-200">
<summary className="flex justify-between items-center cursor-pointer list-none select-none">
<div className="space-y-1">
<span className="font-serif text-xl font-normal text-ink">
{alumni.length}
</span>
<p className="text-xs text-ink-mute font-mono">
2007 2026 (Ph.D.) (M.S.)
</p>
</div>
<span className="font-mono text-xs text-vermillion font-bold border border-vermillion px-3 py-1.5 rounded group-open:bg-vermillion group-open:text-ivory transition-colors">
<span className="group-open:hidden"> </span>
<span className="hidden group-open:inline"> </span>
</span>
</summary>
<div className="mt-6 pt-6 border-t border-line grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{alumni.map((alum, idx) => (
<div
key={idx}
className="bg-ivory p-4 rounded border border-line space-y-1.5"
>
<div className="flex justify-between items-baseline">
<span className="font-serif text-base font-normal text-ink">
{alum.ko} ({alum.en})
</span>
<span className="font-mono text-xs text-ink-mute">
{alum.degree}
</span>
</div>
<div className="font-mono text-xs text-ink-mute flex justify-between">
<span>{alum.graduatedAt}</span>
{alum.major && <span>{alum.major}</span>}
</div>
{alum.currentPosition && (
<div className="text-xs text-cobalt pt-1 border-t border-line/40">
{alum.currentPosition}
</div>
)}
</div>
))}
</div>
</details>
</section>
</div>
);
}
+215
View File
@@ -0,0 +1,215 @@
import React from "react";
import HeroComposition from "./_components/HeroComposition";
import { DirectionsBlock } from "./_components/DirectionsBlock";
import { publications } from "../content/publications";
const PILLARS = [
{
no: "01",
en: "AI Agent Engineering",
ko: "AI 에이전트 3대 핵심 엔지니어링",
theme: "vermillion" as const,
topics: [
"프롬프트 엔지니어링 (System Prompt Optimization)",
"맥락 엔지니어링 (Dynamic Context & Memory Packaging)",
"하네스 엔지니어링 (Agent Control Loop & Sandbox Isolation)",
],
desc: "AI 에이전트의 구동 성능과 안전성을 좌우하는 프롬프트·맥락·하네스 3대 핵심 엔지니어링 기술을 연구합니다.",
},
{
no: "02",
en: "MCP & SKILL Architecture",
ko: "AI Agent 기능 확장 프로토콜",
theme: "cobalt" as const,
topics: [
"Model Context Protocol (MCP) 서버/클라이언트 아키텍처",
"SKILL 도구 캡슐화 및 재사용 패키징",
"CLI 에이전트 인터페이스 제어 및 웹 가동 제어",
],
desc: "에이전트가 외부 도구 및 시스템과 표준화된 방식으로 연동할 수 있도록 MCP와 SKILL 패키징 기술을 개발합니다.",
},
{
no: "03",
en: "Multi-Agent Orchestration",
ko: "멀티 에이전트 협업 및 오케스트레이션",
theme: "vermillion" as const,
topics: [
"HERDR 백그라운드 프로세스 컨테이너 격리 제어",
"crewAI 기반 역할 분담 및 태스크 위임 체계",
"LangGraph 순환 상태 그래프 기반 워크플로우 제어",
],
desc: "다중 에이전트 환경에서 독립적인 역할 분담과 선순환 오케스트레이션을 보장하는 자율 협업 플랫폼을 연구합니다.",
},
{
no: "04",
en: "A2A & ACP Open Protocols",
ko: "에이전트 상호운용성 개방형 표준",
theme: "cobalt" as const,
topics: [
"Agent-to-Agent (A2A) 프로토콜 규격 정의 및 검증",
"Agent Communication Protocol (ACP) 메시지 교환 규격",
"Agent Card (/.well-known/agent-card.json) 메타데이터 검증",
],
desc: "서로 다른 프레임워크 기반의 에이전트 간의 상호운용성을 보장하는 국제 표준 개방형 통신 프로토콜을 구현합니다.",
},
{
no: "05",
en: "High-Performance Networking Backbone",
ko: "AIoT & 고성능 통신 백본",
theme: "vermillion" as const,
topics: [
"gRPC / QUIC 양방향 스트리밍 에이전트 백본 통신",
"Protocol Buffers (Protobuf) 직렬화 통신 최적화",
"MQTT / CoAP 엣지 메시 통신망 통합",
],
desc: "초저지연 양방향 스트리밍 통신 인프라를 바탕으로 고성능 에이전트 백본 네트워크를 설계하고 실증합니다.",
},
];
export default function HomePage() {
const pubCount = publications.length;
return (
<div className="space-y-16 py-6">
{/* Hero Section */}
<section className="relative">
<div className="flex items-center gap-3 mb-4">
<span className="h-px w-8 bg-vermillion"></span>
<span className="font-mono text-xs tracking-widest uppercase text-vermillion font-bold">
Kyungpook National University · AI Agent Networking Lab (ANL)
</span>
</div>
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-start">
<div className="lg:col-span-7 space-y-6">
<h1 className="font-serif text-4xl sm:text-5xl lg:text-6xl font-normal text-ink leading-tight">
<br />
<span className="italic font-serif text-vermillion"> </span>
</h1>
<p className="text-ink-mute text-base sm:text-lg leading-relaxed max-w-2xl">
AI (ANL) , MCP/SKILL ,
, A2A/ACP , gRPC/QUIC
5 .
</p>
{/* Metrics Row (Derived from data array, AC-13) */}
<div className="pt-6 border-t border-line grid grid-cols-3 gap-4">
<div>
<div className="font-serif text-3xl text-vermillion font-normal">
{PILLARS.length}
</div>
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1">
Core Pillars
</div>
</div>
<div>
<div className="font-serif text-3xl text-cobalt font-normal">
{pubCount}
</div>
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1">
Publications
</div>
</div>
<div>
<div className="font-serif text-3xl text-ink font-normal">
2026
</div>
<div className="font-mono text-xs text-ink-mute uppercase tracking-wider mt-1">
Issue Static
</div>
</div>
</div>
</div>
<div className="lg:col-span-5 border border-line bg-paper p-4 rounded-lg">
<HeroComposition />
</div>
</div>
</section>
{/* 5 Pillars Magazine Spread Grid */}
<section className="space-y-8 pt-8 border-t border-line">
<div className="flex justify-between items-end">
<div>
<div className="font-mono text-xs text-vermillion uppercase tracking-widest font-bold">
Research Pillars
</div>
<h2 className="font-serif text-3xl font-normal text-ink mt-1">
5
</h2>
</div>
<div className="font-mono text-xs text-ink-mute">
Magazine Layout 0105
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-6 gap-6">
{PILLARS.map((pillar, idx) => {
const isVermillion = pillar.theme === "vermillion";
const colSpan = idx < 3 ? "lg:col-span-2" : "lg:col-span-3";
return (
<div
key={pillar.no}
className={`${colSpan} bg-paper p-6 rounded-lg border border-line flex flex-col justify-between hover:border-ink transition-colors duration-200`}
>
<div className="space-y-4">
<div className="flex justify-between items-center">
<span
className={`font-mono text-sm font-bold ${
isVermillion ? "text-vermillion" : "text-cobalt"
}`}
>
[{pillar.no}]
</span>
<span className="font-mono text-xs text-ink-mute uppercase">
{pillar.en}
</span>
</div>
<h3 className="font-serif text-xl font-normal text-ink">
{pillar.ko}
</h3>
<p className="text-xs text-ink-mute leading-relaxed">
{pillar.desc}
</p>
<ul className="space-y-2 pt-2">
{pillar.topics.map((topic, tIdx) => (
<li
key={tIdx}
className="text-xs text-ink flex items-start gap-2"
>
<span
className={`inline-block w-1.5 h-1.5 rounded-full mt-1 ${
isVermillion ? "bg-vermillion" : "bg-cobalt"
}`}
></span>
<span>{topic}</span>
</li>
))}
</ul>
</div>
<div className="mt-6 pt-4 border-t border-line/60 flex justify-between items-center text-xs font-mono text-ink-mute">
<span>ANL Core Spec</span>
<span
className={
isVermillion ? "text-vermillion" : "text-cobalt"
}
>
Pillar #{pillar.no}
</span>
</div>
</div>
);
})}
</div>
</section>
{/* Directions Block */}
<DirectionsBlock />
</div>
);
}
@@ -0,0 +1,146 @@
import React from "react";
import { notFound } from "next/navigation";
import { CategoryNav } from "../_components/CategoryNav";
import { publications, patents } from "../../../content/publications";
import { PUB_CATEGORIES } from "../../../content/categories";
import { PubCategory } from "../../../content/types";
interface PageProps {
params: {
category: string;
};
}
// SSG static pre-rendering (● SSG) for Next.js 14
export function generateStaticParams() {
return PUB_CATEGORIES.map((cat) => ({
category: cat.slug,
}));
}
export default function PublicationCategoryPage({ params }: PageProps) {
const { category } = params;
const currentCat = PUB_CATEGORIES.find((c) => c.slug === category);
if (!currentCat) {
notFound();
}
const slug = category as PubCategory;
let records: any[] = [];
if (slug === "patent") {
records = patents.map((p) => ({
title: p.title,
inventors: p.inventors,
appNo: p.applicationNo,
appDate: p.applicationAt,
regNo: p.registrationNo,
regDate: p.registrationAt,
country: p.country,
publishedAt: p.publishedAt,
isPatent: true,
}));
} else {
records = publications
.filter((p) => p.category === slug)
.map((p) => ({
title: p.title,
venue: p.venue,
volume: p.volume,
publishedAt: p.publishedAt,
kci: p.kci,
isPatent: false,
}));
}
return (
<div className="space-y-16 py-6">
{/* Header */}
<section className="space-y-3">
<div className="flex items-center gap-3">
<span className="h-px w-8 bg-vermillion"></span>
<span className="font-mono text-xs tracking-widest uppercase text-vermillion font-bold">
Publications Category
</span>
</div>
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink">
{currentCat.label}
</h1>
<p className="text-ink-mute text-base max-w-2xl">
{currentCat.desc} {records.length} .
</p>
</section>
{/* Category Nav */}
<CategoryNav currentCategory={slug} />
{/* Record List Section */}
<section className="space-y-6">
<div className="flex justify-between items-center border-b border-line pb-3">
<span className="font-mono text-xs text-ink-mute uppercase">
Showing {records.length} Pre-rendered Records
</span>
<span className="font-mono text-xs text-vermillion font-bold">
SSG Static HTML
</span>
</div>
{records.length === 0 ? (
<div className="bg-paper p-8 rounded-lg border border-line text-center space-y-3">
<p className="font-serif text-lg text-ink">
0.
</p>
<p className="text-xs text-ink-mute font-mono">
(D-01 )
</p>
</div>
) : (
<div className="space-y-4">
{records.map((rec, idx) => (
<div
key={idx}
className="bg-paper p-6 rounded-lg border border-line space-y-3 hover:border-vermillion transition-colors"
>
<div className="flex justify-between items-start gap-4">
<h3 className="font-serif text-xl font-normal text-ink leading-snug">
{rec.title}
</h3>
<span className="font-mono text-xs text-vermillion bg-ivory border border-line px-2.5 py-1 rounded shrink-0 font-bold">
{rec.publishedAt}
</span>
</div>
{rec.isPatent ? (
<div className="space-y-1 text-xs text-ink-mute font-mono">
<p className="text-ink">: {rec.inventors}</p>
<p>
: {rec.appNo} ({rec.country}, {rec.appDate})
</p>
{rec.regNo && (
<p className="text-cobalt font-bold">
: {rec.regNo} ({rec.regDate})
</p>
)}
</div>
) : (
<div className="space-y-1 text-xs text-ink-mute font-mono">
<p className="text-ink font-serif italic">{rec.venue}</p>
<div className="flex items-center gap-3">
<span>{rec.volume}</span>
{rec.kci && (
<span className="bg-cobalt text-ivory text-[0.65rem] px-1.5 py-0.5 rounded font-bold">
KCI
</span>
)}
</div>
</div>
)}
</div>
))}
</div>
)}
</section>
</div>
);
}
@@ -0,0 +1,45 @@
import React from "react";
import Link from "next/link";
import { PUB_CATEGORIES } from "../../../content/categories";
import { PubCategory } from "../../../content/types";
interface CategoryNavProps {
currentCategory?: PubCategory;
totalCount?: number;
}
export function CategoryNav({ currentCategory, totalCount }: CategoryNavProps) {
return (
<div className="space-y-4">
<div className="flex flex-wrap items-center gap-2 border-b border-line pb-4">
<Link
href="/publications"
className={`px-4 py-2 rounded text-xs font-mono tracking-wider transition-colors ${
!currentCategory
? "bg-ink text-ivory font-bold"
: "bg-paper text-ink border border-line hover:border-ink"
}`}
>
All Overview {!currentCategory && totalCount ? `(${totalCount})` : ""}
</Link>
{PUB_CATEGORIES.map((cat) => {
const isActive = currentCategory === cat.slug;
return (
<Link
key={cat.slug}
href={`/publications/${cat.slug}`}
className={`px-4 py-2 rounded text-xs font-mono tracking-wider transition-colors ${
isActive
? "bg-vermillion text-ivory font-bold"
: "bg-paper text-ink border border-line hover:border-vermillion"
}`}
>
{cat.label}
</Link>
);
})}
</div>
</div>
);
}
+124 -159
View File
@@ -1,173 +1,138 @@
import type { Metadata } from "next";
import PageHeader from "@/components/PageHeader";
import Reveal from "@/components/Reveal";
import SectionLabel from "@/components/SectionLabel";
import Counter from "@/components/Counter";
import Marquee from "@/components/Marquee";
import React from "react";
import Link from "next/link";
import { CategoryNav } from "./_components/CategoryNav";
import { publications, patents } from "../../content/publications";
import { PUB_CATEGORIES } from "../../content/categories";
export const metadata: Metadata = {
title: "논문 (Publications)",
description: "AI 에이전트 네트워크 연구실 (ANL)의 대표 논문 목록 (placeholder).",
};
export default function PublicationsIndexPage() {
const allRecords = [
...publications.map((p) => ({ ...p, type: "paper" as const })),
...patents.map((p) => ({
category: "patent" as const,
title: p.title,
venue: `발명자: ${p.inventors} (출원번호: ${p.applicationNo})`,
volume: p.registrationNo ? `등록번호: ${p.registrationNo}` : `출원국가: ${p.country}`,
publishedAt: p.publishedAt,
type: "patent" as const,
})),
];
// CUSTOMIZATION HOOK: replace placeholder publications below.
const publications = [
{
year: "2025",
type: "Journal",
title:
"메타버스 상호운용을 위한 공통 정보 모델 설계 및 oneM2M 매핑 (Design of a Common Information Model for Metaverse Interoperability over oneM2M)",
authors: "Hong G., Researcher A., et al.",
venue: "한국통신학회논문지 (J-KICS), Vol. 50, No. 3",
},
{
year: "2025",
type: "Conference",
title:
"QUIC-based Orchestration Architecture for Low-Latency Multi-Agent Communication",
authors: "Researcher B., Hong G.",
venue: "IEEE International Conference on Communications (ICC)",
},
{
year: "2024",
type: "Journal",
title:
"W3C WoT Thing Description를 활용한 이종 메타버스 자산의 의미 보존 변환 (Semantic-Preserving Mapping of Cross-Platform Metaverse Assets Using W3C WoT)",
authors: "Researcher C., Hong G., et al.",
venue: "정보과학회논문지 (KIISE Transactions), Vol. 51, No. 11",
},
{
year: "2024",
type: "Conference",
title:
"Stream Multiplexing Strategies for Agent Message Routing over QUIC",
authors: "Researcher D., Researcher B., Hong G.",
venue: "ACM/IEEE Symposium on Edge Computing (SEC)",
},
{
year: "2023",
type: "Conference",
title:
"oneM2M 기반 IoT 디바이스 상호운용성 적합성 검증 프레임워크 (A Conformance Testing Framework for oneM2M-based IoT Interoperability)",
authors: "Researcher E., Hong G.",
venue: "한국정보과학회 학술발표회 (KSC)",
},
];
// Sort by publishedAt descending
const sortedRecords = [...allRecords].sort(
(a, b) => new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime()
);
// CUSTOMIZATION HOOK: venue ticker.
const venueTicker = [
"J-KICS",
"IEEE ICC",
"KIISE TRANSACTIONS",
"ACM/IEEE SEC",
"KSC",
"oneM2M",
"W3C WoT",
"IETF QUIC",
];
const recentRecords = sortedRecords.slice(0, 10);
// Accent per publication type, drawn from the editorial palette.
const typeAccent: Record<string, { text: string; rule: string }> = {
Journal: { text: "text-vermillion", rule: "bg-vermillion" },
Conference: { text: "text-cobalt", rule: "bg-cobalt" },
};
const getCategoryCount = (slug: string) => {
if (slug === "patent") return patents.length;
return publications.filter((p) => p.category === slug).length;
};
// Derived figures.
const journalCount = publications.filter((p) => p.type === "Journal").length;
const confCount = publications.filter((p) => p.type === "Conference").length;
const figures = [
{ value: publications.length, label: "전체 논문 · Total Publications" },
{ value: journalCount, label: "저널 · Journal" },
{ value: confCount, label: "학회 · Conference" },
];
export default function PublicationsPage() {
return (
<>
<PageHeader
ko="논문"
en="Publications"
index={3}
description="메타버스 상호운용성(MCM)과 QUIC 기반 멀티에이전트 통신 분야의 대표 논문입니다. 아래 목록은 예시(placeholder)입니다."
/>
<div className="space-y-16 py-6">
{/* Header */}
<section className="space-y-3">
<div className="flex items-center gap-3">
<span className="h-px w-8 bg-vermillion"></span>
<span className="font-mono text-xs tracking-widest uppercase text-vermillion font-bold">
Research Output &amp; Patents
</span>
</div>
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink">
</h1>
<p className="text-ink-mute text-base max-w-2xl">
· 148 75 {allRecords.length} .
</p>
</section>
{/* Venue marquee band */}
<Reveal>
<Marquee
items={venueTicker}
reverse
className="border-b border-ink bg-ink py-3 font-display text-xl tracking-wide text-ivory"
/>
</Reveal>
{/* Category Nav */}
<CategoryNav totalCount={allRecords.length} />
{/* ============ FIGURES ============ */}
<section className="border-b border-ink">
<div className="container-content grid gap-px bg-line sm:grid-cols-3">
{figures.map((f, i) => (
<Reveal key={f.label} delay={i * 100} className="bg-ivory">
<div className="px-6 py-10">
<Counter value={f.value} className="display block text-ink" />
<p className="kicker mt-3">{f.label}</p>
{/* Category Cards Overview */}
<section className="space-y-6">
<h2 className="font-serif text-2xl font-normal text-ink">
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{PUB_CATEGORIES.map((cat) => {
const count = getCategoryCount(cat.slug);
return (
<div
key={cat.slug}
className="bg-paper p-6 rounded-lg border border-line flex flex-col justify-between hover:border-vermillion transition-colors"
>
<div className="space-y-3">
<div className="flex justify-between items-baseline">
<span className="font-mono text-xs text-vermillion font-bold uppercase">
Category
</span>
<span className="font-serif text-2xl font-normal text-ink">
{count}
</span>
</div>
<h3 className="font-serif text-xl font-normal text-ink">
{cat.label}
</h3>
<p className="text-xs text-ink-mute leading-relaxed">
{cat.desc}
</p>
</div>
<div className="mt-6 pt-4 border-t border-line flex justify-between items-center">
<span className="font-mono text-xs text-ink-mute">
SSG Pre-rendered
</span>
<Link
href={`/publications/${cat.slug}`}
className="font-mono text-xs text-vermillion font-bold hover:underline"
>
({count})
</Link>
</div>
</div>
</Reveal>
);
})}
</div>
</section>
{/* Recent 10 Highlight Records */}
<section className="space-y-6 pt-6 border-t border-line">
<div className="flex justify-between items-end">
<h2 className="font-serif text-2xl font-normal text-ink">
(Top 10)
</h2>
<span className="font-mono text-xs text-ink-mute">
Total {allRecords.length} Records
</span>
</div>
<div className="space-y-4">
{recentRecords.map((rec, idx) => (
<div
key={idx}
className="bg-paper p-5 rounded border border-line space-y-2"
>
<div className="flex justify-between items-start gap-4">
<h3 className="font-serif text-lg font-normal text-ink leading-snug">
{rec.title}
</h3>
<span className="font-mono text-xs text-vermillion bg-ivory border border-line px-2 py-0.5 rounded shrink-0">
{rec.publishedAt}
</span>
</div>
<div className="text-xs text-ink-mute font-mono">
{rec.venue}
</div>
{rec.volume && (
<div className="text-xs text-ink-mute font-mono">
{rec.volume}
</div>
)}
</div>
))}
</div>
</section>
{/* ============ PUBLICATION LIST ============ */}
<section>
<div className="container-content py-16 sm:py-24">
<Reveal>
<SectionLabel index={1} label="Selected Works" />
</Reveal>
<ol className="mt-12 border-t border-ink">
{publications.map((p, i) => {
const accent = typeAccent[p.type] ?? {
text: "text-ink",
rule: "bg-ink",
};
// Reveal `as="li"` keeps the <ol> direct-child contract (HTML spec:
// <ol> may only contain <li>/<script>/<template>). See REVIEW.md §3 #1.
return (
<Reveal
as="li"
key={p.title}
delay={(i % 3) * 80}
className="group grid gap-6 border-b border-ink py-8 transition-colors duration-500 hover:bg-paper sm:grid-cols-12 sm:py-10"
>
{/* Index + year rail */}
<div className="flex items-baseline gap-4 sm:col-span-3 sm:flex-col sm:gap-3">
<span className="font-display text-5xl leading-none text-ink-mute">
{String(i + 1).padStart(2, "0")}
</span>
<span className="font-display text-2xl italic text-ink">
{p.year}
</span>
<span
className={`inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.16em] ${accent.text}`}
>
<span className={`h-1.5 w-1.5 rounded-full ${accent.rule}`} />
{p.type}
</span>
</div>
{/* Title + meta */}
<div className="sm:col-span-9">
<h3 className="headline-ko text-xl leading-snug text-ink sm:text-2xl">
{p.title}
</h3>
<p className="mt-3 text-sm text-ink-soft">{p.authors}</p>
<p className="font-display text-sm italic text-ink-mute">
{p.venue}
</p>
</div>
</Reveal>
);
})}
</ol>
</div>
</section>
</>
</div>
);
}
+11
View File
@@ -0,0 +1,11 @@
import { MetadataRoute } from "next";
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: "*",
allow: "/",
},
sitemap: "https://anl.knu.ac.kr/sitemap.xml",
};
}
+48
View File
@@ -0,0 +1,48 @@
import { MetadataRoute } from "next";
import { PUB_CATEGORIES } from "../content/categories";
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = "https://anl.knu.ac.kr";
const staticRoutes: MetadataRoute.Sitemap = [
{
url: `${baseUrl}`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 1.0,
},
{
url: `${baseUrl}/members`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.8,
},
{
url: `${baseUrl}/publications`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.9,
},
{
url: `${baseUrl}/lectures`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.7,
},
{
url: `${baseUrl}/standardization`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.8,
},
];
const categoryRoutes: MetadataRoute.Sitemap = PUB_CATEGORIES.map((cat) => ({
url: `${baseUrl}/publications/${cat.slug}`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.8,
}));
return [...staticRoutes, ...categoryRoutes];
}
+103 -159
View File
@@ -1,173 +1,117 @@
import type { Metadata } from "next";
import PageHeader from "@/components/PageHeader";
import Reveal from "@/components/Reveal";
import SectionLabel from "@/components/SectionLabel";
import Counter from "@/components/Counter";
import Marquee from "@/components/Marquee";
export const metadata: Metadata = {
title: "표준화 활동 (Standardization)",
description:
"oneM2M, W3C WoT, IETF QUIC, OMA LwM2M 등 국제 표준화 기구에서의 연구실 기여 활동 (placeholder).",
};
// CUSTOMIZATION HOOK: replace placeholder standardization activities below.
const bodies = [
{
org: "oneM2M",
full: "oneM2M Partnership Project",
area: "IoT 서비스 계층 표준",
accent: "vermillion" as const,
contributions: [
"메타버스 상호운용을 위한 공통 정보 모델(CIM) 기고 (placeholder)",
"디바이스 상호운용성 적합성 테스트 케이스 제안",
],
},
{
org: "W3C WoT",
full: "W3C Web of Things",
area: "Thing Description / 시맨틱",
accent: "cobalt" as const,
contributions: [
"메타버스 자산의 Thing Description 매핑 프로파일 제안 (placeholder)",
"의미 보존 변환 가이드라인 논의 참여",
],
},
{
org: "IETF QUIC",
full: "IETF QUIC Working Group",
area: "전송 프로토콜",
accent: "vermillion" as const,
contributions: [
"멀티에이전트 환경을 위한 스트림 우선순위 확장 검토 (placeholder)",
"연결 마이그레이션 활용 사례 기여",
],
},
{
org: "OMA LwM2M",
full: "OMA SpecWorks Lightweight M2M",
area: "경량 디바이스 관리",
accent: "cobalt" as const,
contributions: [
"엣지 에이전트 디바이스 관리 객체 정의 제안 (placeholder)",
"리소스 모델 상호운용성 검토",
],
},
];
// CUSTOMIZATION HOOK: standards-body ticker.
const orgTicker = [
"oneM2M",
"W3C WoT",
"IETF QUIC",
"OMA LwM2M",
"CONFORMANCE",
"INTEROPERABILITY",
"SEMANTIC MAPPING",
];
const totalContributions = bodies.reduce(
(n, b) => n + b.contributions.length,
0
);
const figures = [
{ value: bodies.length, label: "표준화 기구 · Standards Bodies" },
{ value: totalContributions, label: "기여 항목 · Contributions" },
{ value: 4, label: "기술 영역 · Technical Areas" },
];
const accentText: Record<string, string> = {
vermillion: "text-vermillion",
cobalt: "text-cobalt",
};
const accentDot: Record<string, string> = {
vermillion: "bg-vermillion",
cobalt: "bg-cobalt",
};
import React from "react";
import { standardsBodies } from "../../content/standards";
export default function StandardizationPage() {
const totalDocs = standardsBodies.reduce(
(acc, body) =>
acc + body.projects.reduce((pAcc, proj) => pAcc + proj.documents.length, 0),
0
);
return (
<>
<PageHeader
ko="표준화 활동"
en="Standardization"
index={5}
description="국제 표준화 기구와 협력하여 연구 결과를 표준에 반영합니다. 아래 기여 내역은 예시(placeholder)이며 실제 활동으로 교체할 수 있습니다."
/>
{/* Standards-body marquee band */}
<Reveal>
<Marquee
items={orgTicker}
className="border-b border-ink bg-ink py-3 font-display text-xl tracking-wide text-ivory"
/>
</Reveal>
{/* ============ FIGURES ============ */}
<section className="border-b border-ink">
<div className="container-content grid gap-px bg-line sm:grid-cols-3">
{figures.map((f, i) => (
<Reveal key={f.label} delay={i * 100} className="bg-ivory">
<div className="px-6 py-10">
<Counter value={f.value} className="display block text-ink" />
<p className="kicker mt-3">{f.label}</p>
</div>
</Reveal>
))}
<div className="space-y-16 py-6">
{/* Header */}
<section className="space-y-3">
<div className="flex items-center gap-3">
<span className="h-px w-8 bg-vermillion"></span>
<span className="font-mono text-xs tracking-widest uppercase text-vermillion font-bold">
Open Standards &amp; Contributions
</span>
</div>
<h1 className="font-serif text-4xl sm:text-5xl font-normal text-ink">
</h1>
<p className="text-ink-mute text-base max-w-2xl">
IEC TC100, ISO/IEC JTC1, ITU-T, TTA / {standardsBodies.length} {totalDocs} .
</p>
</section>
{/* ============ CONTRIBUTIONS BY BODY ============ */}
<section>
<div className="container-content py-16 sm:py-24">
<Reveal>
<SectionLabel index={1} label="Contributions" />
</Reveal>
{/* Standards Bodies Section */}
<section className="space-y-12 pt-6 border-t border-line">
{standardsBodies.map((body, idx) => (
<div key={idx} className="bg-paper p-8 rounded-lg border border-line space-y-6">
<div className="flex flex-wrap justify-between items-start gap-4 border-b border-line pb-4">
<div>
<div className="flex items-center gap-2">
<span className="font-mono text-xs text-vermillion font-bold uppercase">
[{body.scope}]
</span>
{body.role && (
<span className="bg-vermillion text-ivory font-mono text-[0.65rem] px-2 py-0.5 rounded font-bold">
{body.role}
</span>
)}
</div>
<h2 className="font-serif text-2xl font-normal text-ink mt-1">
{body.org}
</h2>
<p className="text-xs text-ink-mute font-mono mt-0.5">
{body.full} ({body.period})
</p>
</div>
<div className="mt-12 grid gap-px bg-line sm:grid-cols-2">
{bodies.map((b, i) => (
<Reveal
key={b.org}
variant={i % 2 === 0 ? "left" : "right"}
delay={(i % 2) * 100}
className="bg-ivory"
>
<article className="group flex h-full flex-col border border-ink p-8 transition-colors duration-500 hover:bg-ink hover:text-ivory sm:p-10">
<div className="flex items-baseline justify-between gap-3">
<h3 className="headline-ko text-3xl">{b.org}</h3>
<span className="font-display text-4xl text-ink-mute group-hover:text-ivory/40">
{String(i + 1).padStart(2, "0")}
<div className="font-mono text-xs text-ink-mute bg-ivory border border-line px-3 py-1.5 rounded">
Projects: {body.projects.length}
</div>
</div>
{/* 3-Tier Hierarchy: Projects & Documents */}
<div className="space-y-6">
{body.projects.map((proj, pIdx) => (
<div key={pIdx} className="bg-ivory p-6 rounded border border-line space-y-3">
<div className="font-serif text-lg font-normal text-ink border-b border-line/60 pb-2 flex justify-between items-center">
<div>
<span className="font-mono text-xs text-cobalt font-bold mr-2">
{proj.wg}
</span>
<span>{proj.name}</span>
</div>
<span className="font-mono text-xs text-ink-mute">
{proj.documents.length} Docs
</span>
</div>
<p className="font-display mt-1 text-sm italic opacity-70">{b.full}</p>
<p
className={`mt-4 inline-flex w-fit border px-3 py-1 text-xs font-semibold uppercase tracking-[0.16em] ${
b.accent === "vermillion"
? "border-vermillion/40"
: "border-cobalt/40"
} ${accentText[b.accent]} group-hover:border-ivory/40 group-hover:text-ivory`}
>
{b.area}
</p>
<ul className="mt-6 space-y-4 border-t border-ink/20 pt-6 text-sm group-hover:border-ivory/20">
{b.contributions.map((c) => (
<li key={c} className="flex gap-3">
<span
aria-hidden
className={`mt-1.5 h-1.5 w-1.5 flex-none rounded-full ${accentDot[b.accent]} group-hover:bg-ivory`}
/>
<span className="leading-relaxed opacity-90">{c}</span>
</li>
))}
</ul>
</article>
</Reveal>
))}
{proj.documents.length > 0 ? (
<div className="space-y-3 pt-1">
{proj.documents.map((doc, dIdx) => (
<div
key={dIdx}
className="bg-paper p-4 rounded border border-line/60 space-y-1.5"
>
<div className="flex justify-between items-start gap-4">
<h3 className="font-serif text-base font-normal text-ink leading-snug">
&ldquo;{doc.title}&rdquo;
</h3>
<span
className={`font-mono text-[0.65rem] px-2 py-0.5 rounded font-bold shrink-0 ${
doc.status === "InProgress"
? "bg-vermillion text-ivory"
: "bg-cobalt text-ivory"
}`}
>
{doc.status}
</span>
</div>
<div className="font-mono text-xs text-ink-mute flex justify-between">
<span>{doc.ref}</span>
{doc.publishedAt && (
<span className="text-ink">{doc.publishedAt}</span>
)}
</div>
</div>
))}
</div>
) : (
<div className="text-xs text-ink-mute font-mono italic">
</div>
)}
</div>
))}
</div>
</div>
</div>
))}
</section>
</>
</div>
);
}
+3 -3
View File
@@ -6,7 +6,7 @@ import { useState } from "react";
// CUSTOMIZATION HOOK: edit nav labels / routes here.
const navItems = [
{ href: "/intro", ko: "연구실 소개", en: "Intro", no: "01" },
{ href: "/", ko: "", en: "Home", no: "01" },
{ href: "/members", ko: "구성원", en: "Members", no: "02" },
{ href: "/publications", ko: "논문", en: "Publications", no: "03" },
{ href: "/lectures", ko: "강의", en: "Lectures", no: "04" },
@@ -18,7 +18,7 @@ export default function Header() {
const pathname = usePathname();
const isActive = (href: string) =>
pathname === href || pathname.startsWith(`${href}/`);
href === "/" ? pathname === "/" : pathname === href || pathname.startsWith(`${href}/`);
return (
<header className="sticky top-0 z-50 border-b border-ink bg-ivory/85 backdrop-blur">
@@ -37,7 +37,7 @@ export default function Header() {
<div className="container-content flex h-[4.25rem] items-center justify-between">
{/* Brand */}
<Link
href="/intro"
href="/"
className="group flex flex-col leading-none"
onClick={() => setOpen(false)}
>
+31
View File
@@ -0,0 +1,31 @@
import { PubCategory } from "./types";
export interface CategoryInfo {
slug: PubCategory;
label: string;
desc: string;
}
// Single source of truth for Publications categories (P-02 / D-01)
export const PUB_CATEGORIES: CategoryInfo[] = [
{
slug: "intl-conf",
label: "International Conference",
desc: "국제 학술대회 발표 및 프로시딩 논문",
},
{
slug: "intl-journal-conf",
label: "International Journal & Conference",
desc: "국제 우수 저널(SCI/E급) 및 학술대회 논문 실적",
},
{
slug: "domestic-journal-conf",
label: "Domestic Journal & Conference",
desc: "국내 등재 학술지(KCI) 및 국내 학술대회 논문 실적",
},
{
slug: "patent",
label: "Patent",
desc: "국내외 지식재산권 출원 및 등록 실적",
},
];
+804
View File
@@ -0,0 +1,804 @@
// AUTO-GENERATED by scripts/extract/generate_all.py — DO NOT EDIT BY HAND
import { Semester } from "./types";
export const semesters: Semester[] = [
{
"term": "Spring",
"year": 2026,
"courses": [
{
"code": "COMP 0414",
"en": "Computer Networks"
},
{
"code": "ITEC 0401",
"en": "Capstone Design Project I"
}
]
},
{
"term": "Fall",
"year": 2025,
"courses": [
{
"code": "COMP 0432",
"en": "Topics in Software"
},
{
"code": "ITEC 0402",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Spring",
"year": 2025,
"courses": [
{
"code": "ITEC 0201",
"en": "Introduction to Computer Science and Engineering"
},
{
"code": "EECS 0312",
"en": "Network Programming"
},
{
"code": "ITEC 0401",
"en": "Capstone Design Project I"
},
{
"code": "COMP 0461",
"en": "Problem-based Engineering Training Experiment"
}
]
},
{
"term": "Fall",
"year": 2024,
"courses": [
{
"code": "COMP 0432",
"en": "Topics in Software"
},
{
"code": "BIDA 0201",
"en": "Big Data Convergence Project"
},
{
"code": "ITEC 0402",
"en": "Capstone Design Project II"
},
{
"code": "COMP 0460",
"en": "Problem-based Engineering Training Experiment"
}
]
},
{
"term": "Spring",
"year": 2024,
"courses": [
{
"code": "BIDA 0201",
"en": "Big Data Convergence Project"
},
{
"code": "ITEC 0401",
"en": "Capstone Design Project I"
}
]
},
{
"term": "Fall",
"year": 2023,
"courses": [
{
"code": "SABBATICAL",
"en": "No Class (Sabbatical)",
"note": "Sabbatical"
}
]
},
{
"term": "Spring",
"year": 2023,
"courses": [
{
"code": "EECS 0312",
"en": "Network Programming"
},
{
"code": "BIDA 0201",
"en": "Big Data Convergence Project"
},
{
"code": "CICT 0703",
"en": "Software Convergence Project 3"
}
]
},
{
"term": "Fall",
"year": 2022,
"courses": [
{
"code": "CLTR 273001",
"en": "Problem Solving and Computing"
},
{
"code": "COMP 432001",
"en": "Topics in Software"
},
{
"code": "ITEC 401001",
"en": "Capstone Design Project I"
}
]
},
{
"term": "Spring",
"year": 2022,
"courses": [
{
"code": "EECS 312002",
"en": "Network Programming"
},
{
"code": "ITEC 402001",
"en": "Capstone Design Project II"
},
{
"code": "COMP 460001",
"en": "Problem-based Engineering Training Experiment"
},
{
"code": "CICT 701001",
"en": "Software Convergence Project 1"
}
]
},
{
"term": "Fall",
"year": 2021,
"courses": [
{
"code": "ITEC 402001",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Spring",
"year": 2021,
"courses": [
{
"code": "CLTR 273001",
"en": "Problem Solving and Computing"
},
{
"code": "GLSO 218001",
"en": "Software Convergence Design 1"
},
{
"code": "ITEC 402001",
"en": "Capstone Design Project II"
},
{
"code": "COMP 778001",
"en": "Advanced Mobile Computing"
}
]
},
{
"term": "Fall",
"year": 2020,
"courses": [
{
"code": "ITEC 401003",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 401004",
"en": "Capstone Design Project I"
},
{
"code": "GLSO 228001",
"en": "Topics in Software Convergence IV"
}
]
},
{
"term": "Spring",
"year": 2020,
"courses": [
{
"code": "ITEC 401016",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402003",
"en": "Capstone Design Project II"
},
{
"code": "COMP 778001",
"en": "Advanced Mobile Computing"
}
]
},
{
"term": "Fall",
"year": 2019,
"courses": [
{
"code": "COMP 432001",
"en": "Topics in Software"
},
{
"code": "ITEC 401003",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402016",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Spring",
"year": 2019,
"courses": [
{
"code": "ITEC 201010",
"en": "Introduction to Computer Science and Engineering"
},
{
"code": "ITEC 401016",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402003",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Fall",
"year": 2018,
"courses": [
{
"code": "ITEC 401005",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402017",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Spring",
"year": 2018,
"courses": [
{
"code": "ITEC 401021",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402006",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Fall",
"year": 2017,
"courses": [
{
"code": "COMP 432001",
"en": "Topics in Software"
},
{
"code": "GLSO 213001",
"en": "Creative Convergence Design"
},
{
"code": "ITEC 401003",
"en": "Capstone Design Project I"
}
]
},
{
"term": "Spring",
"year": 2017,
"courses": [
{
"code": "EECS 312001",
"en": "Network Programming"
},
{
"code": "ITEC 401018",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402005",
"en": "Capstone Design Project II"
},
{
"code": "COME 742001",
"en": "Advanced Computer Networks"
}
]
},
{
"term": "Fall",
"year": 2016,
"courses": [
{
"code": "COMP 432001",
"en": "Topics in Software"
},
{
"code": "COME 331013) and DS Applications (COMP 216002",
"en": "Data Structures"
},
{
"code": "ITEC 401004",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402016",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Spring",
"year": 2016,
"courses": [
{
"code": "COMP 414003",
"en": "Computer Networks"
},
{
"code": "ITEC 401031",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402005",
"en": "Capstone Design Project II"
},
{
"code": "ITEC 402006",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Fall",
"year": 2015,
"courses": [
{
"code": "COMP 432001",
"en": "Topics in Software"
},
{
"code": "ITEC 401006",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 401007",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402022",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Spring",
"year": 2015,
"courses": [
{
"code": "ITEC 201009",
"en": "Introduction to Computer Science and Engineering"
},
{
"code": "EECS 312001",
"en": "Network Programming"
},
{
"code": "EECS 312002",
"en": "Network Programming"
},
{
"code": "ITEC 401021",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402004",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Fall",
"year": 2014,
"courses": [
{
"code": "ITEC 401006",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402021",
"en": "Capstone Design Project II"
},
{
"code": "COME 742001",
"en": "Advanced Computer Networks"
}
]
},
{
"term": "Spring",
"year": 2014,
"courses": [
{
"code": "COMP 414002",
"en": "Computer Networks"
},
{
"code": "ITEC 402004",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Fall",
"year": 2013,
"courses": [
{
"code": "ITEC 401005",
"en": "Capstone Design Project I"
},
{
"code": "ITEC 402017",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Spring",
"year": 2013,
"courses": [
{
"code": "COMP 432001",
"en": "Topics in Software"
},
{
"code": "ITEC 402005",
"en": "Capstone Design Project II"
}
]
},
{
"term": "Fall",
"year": 2012,
"courses": [
{
"code": "COMP 432001",
"en": "Topics in Software"
},
{
"code": "ITEC 401003",
"en": "Capstone Design Project I"
},
{
"code": "EECS 422021",
"en": "Senior Project II"
}
]
},
{
"term": "Spring",
"year": 2012,
"courses": [
{
"code": "COMP 214002",
"en": "Web Programming Design"
},
{
"code": "COMP 749001",
"en": "Computer Network Protocols"
},
{
"code": "ELEC 957001",
"en": "Next Generation Internet Technology"
}
]
},
{
"term": "Fall",
"year": 2011,
"courses": [
{
"code": "COME 311003",
"en": "Probability and Statistics: Class 1"
},
{
"code": "COME 311004",
"en": "Probability and Statistics: Class 2"
},
{
"code": "COMP 764001",
"en": "Internet Computing"
},
{
"code": "COMP 432001",
"en": "Topics in Software"
}
]
},
{
"term": "Spring",
"year": 2011,
"courses": [
{
"code": "COMP 214001",
"en": "Web Programming Design: Class 1"
},
{
"code": "COMP 214002",
"en": "Web Programming Design: Class 2"
}
]
},
{
"term": "Fall",
"year": 2010,
"courses": [
{
"code": "COME 311003",
"en": "Probability and Statistics"
},
{
"code": "COME 331004",
"en": "Data Structures"
},
{
"code": "EECS 422022",
"en": "Senior Project II"
}
]
},
{
"term": "Spring",
"year": 2010,
"courses": [
{
"code": "EECS 450001",
"en": "Internet Programming Design"
},
{
"code": "COMP 414003",
"en": "Computer Networks"
},
{
"code": "ELEC 957001",
"en": "Next-Generation Internet Technology"
},
{
"code": "EECS 408016",
"en": "Senior Project I"
}
]
},
{
"term": "Fall",
"year": 2009,
"courses": [
{
"code": "COME 31103",
"en": "Probability and Statistics"
},
{
"code": "COME 33105",
"en": "Data Structures"
},
{
"code": "EECS 42202",
"en": "Senior Project II"
}
]
},
{
"term": "Spring",
"year": 2009,
"courses": [
{
"code": "EECS 20704",
"en": "Introduction to Computer Science"
},
{
"code": "EECS 45001",
"en": "Internet Programming Design"
},
{
"code": "EECS 40803",
"en": "Senior Project I"
}
]
},
{
"term": "Fall",
"year": 2008,
"courses": [
{
"code": "COME 31103",
"en": "Probability and Statistics"
},
{
"code": "COMP 76401",
"en": "Internet Computing"
},
{
"code": "ELEC 75401",
"en": "Computer Network: Special"
}
]
},
{
"term": "Spring",
"year": 2008,
"courses": [
{
"code": "EECS 31401",
"en": "Internet Programming and Practices"
},
{
"code": "COMP 74901",
"en": "Computer Network Protocols"
}
]
},
{
"term": "Fall",
"year": 2007,
"courses": [
{
"code": "EECS 20703",
"en": "Introduction to Computer Science"
},
{
"code": "COME 31103",
"en": "Probability and Statistics"
},
{
"code": "COMP 41401",
"en": "Computer Networks"
}
]
},
{
"term": "Spring",
"year": 2007,
"courses": [
{
"code": "EECS 20109",
"en": "C Programming and Practices"
},
{
"code": "EECS 20704",
"en": "Introduction to Computer Science"
},
{
"code": "EECS 31401",
"en": "Internet Programming and Practices"
}
]
},
{
"term": "Fall",
"year": 2006,
"courses": [
{
"code": "EECS 20703",
"en": "Introduction to Computer Science"
},
{
"code": "COME 31103",
"en": "Probability and Statistics"
},
{
"code": "COMP 76401",
"en": "Internet Computing"
}
]
},
{
"term": "Spring",
"year": 2006,
"courses": [
{
"code": "EECS 20704",
"en": "Introduction to Computer Science"
},
{
"code": "EECS 31401",
"en": "Internet Programming and Practices"
},
{
"code": "COMP 75101",
"en": "Computer Performance Analysis"
}
]
},
{
"term": "Fall",
"year": 2005,
"courses": [
{
"code": "EECS 20703",
"en": "Introduction to Computer Science"
},
{
"code": "EECS 20806",
"en": "Data Structures"
},
{
"code": "COMP 41402",
"en": "Computer Network"
}
]
},
{
"term": "Spring",
"year": 2005,
"courses": [
{
"code": "EECS 20704",
"en": "Introduction to Computer Science"
},
{
"code": "EECS 49201",
"en": "Internet Programming Design"
},
{
"code": "COMP 74901",
"en": "Computer Network Protocols"
}
]
},
{
"term": "Fall",
"year": 2004,
"courses": [
{
"code": "ELEC 26104",
"en": "Computer Engineering"
},
{
"code": "COMP 22101",
"en": "Data Structures II"
},
{
"code": "EECS 31201",
"en": "Network Programming"
}
]
},
{
"term": "Spring",
"year": 2004,
"courses": [
{
"code": "EECS 20704",
"en": "Introduction to Computer Science"
},
{
"code": "COMP 21105",
"en": "Data Structures I"
}
]
}
];
+544
View File
@@ -0,0 +1,544 @@
// AUTO-GENERATED by scripts/extract/generate_all.py — DO NOT EDIT BY HAND
import { Member, Alumnus } from "./types";
export const activeMembers: Member[] = [
{
"ko": "Seok-Joo Koh (고석주, Professor): &",
"en": "Seok-Joo Koh (고석주, Professor): &",
"degree": "MSStudent"
},
{
"ko": "최동규",
"en": "Dong-Kyu Choi",
"degree": "PhD"
},
{
"ko": "남혜빈",
"en": "Hye-Been Nam",
"degree": "PhDCandidate"
},
{
"ko": "임도현",
"en": "Dohyeon Lim",
"degree": "PhDStudent"
},
{
"ko": "최준혁",
"en": "Jun-Hyeok Choi",
"degree": "PhDStudent"
},
{
"ko": "신광선",
"en": "Gwang-Seon Shin",
"degree": "MSCandidate"
},
{
"ko": "이환웅",
"en": "Hwan-Woong Lee",
"degree": "MSStudent"
},
{
"ko": "Hoang Anh Dang",
"en": "Hoang Anh Dang",
"degree": "MSStudent"
},
{
"ko": "김민희",
"en": "Minhee Kim",
"degree": "PhDCandidate",
"affiliation": "School of Computer Science and Engineering"
},
{
"ko": "김근솔",
"en": "Keun-Sol Kim",
"degree": "PhDCandidate",
"affiliation": "Department of Information Security"
},
{
"ko": "민성준",
"en": "Sung-Jun Min",
"degree": "PhDCandidate",
"affiliation": "Department of Information Science"
},
{
"ko": "최진원",
"en": "Jin-Won Choi",
"degree": "PhDStudent",
"affiliation": "Department of Science and Technology"
},
{
"ko": "정기수",
"en": "Ki-Soo Jung",
"degree": "PhDStudent",
"affiliation": "Department of Science and Technology"
},
{
"ko": "이미주",
"en": "Mi-Joo Lee",
"degree": "PhDStudent",
"affiliation": "Department of ICT Convergence"
},
{
"ko": "박유나",
"en": "Yunah Park",
"degree": "MSCandidate",
"affiliation": "Department of Information Security"
},
{
"ko": "박채영",
"en": "Chae-Young Park",
"degree": "MSCandidate",
"affiliation": "Department of Information Science"
}
];
export const alumni: Alumnus[] = [
{
"ko": "김동주",
"en": "Dongju Kim",
"degree": "PhD",
"graduatedAt": "2026-08",
"major": "Computer Science and Engineering",
"currentPosition": "He is now with Daegu Catholic University (대구가톨릭대학교) as Professor"
},
{
"ko": "황정미",
"en": "Jung-Mi Hwang",
"degree": "MS",
"graduatedAt": "2026-08",
"major": "Information Science",
"currentPosition": "She is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "배드로",
"en": "Dro Bae",
"degree": "MS",
"graduatedAt": "2026-02",
"major": "Industrial Engineering",
"currentPosition": "He is now with SK AX"
},
{
"ko": "권세기",
"en": "Se-Gi Kwon",
"degree": "MS",
"graduatedAt": "2026-02",
"major": "Information Security",
"currentPosition": "He is now with J Solution (제이솔루션) as CEO"
},
{
"ko": "조세현",
"en": "Se-Hyun Cho",
"degree": "PhD",
"graduatedAt": "2025-08",
"major": "Information Security",
"currentPosition": "He is now with Cyber Security Center"
},
{
"ko": "김윤성",
"en": "Yun-Seong Kim",
"degree": "MS",
"graduatedAt": "2025-08",
"major": "Data Convergence Computing",
"currentPosition": "He is now with SL (에스엘)"
},
{
"ko": "김수진",
"en": "Su-Jin Kim",
"degree": "MS",
"graduatedAt": "2025-08",
"major": "Information Science",
"currentPosition": "He is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "김상태",
"en": "Sang-Tae Kim",
"degree": "MS",
"graduatedAt": "2025-08",
"major": "Industrial Engineering",
"currentPosition": "He is now with Oh-Sung Electronis (오성전자)"
},
{
"ko": "김규범",
"en": "Gyu-Bum Kim",
"degree": "MS",
"graduatedAt": "2025-08",
"major": "Computer Science and Engineering",
"currentPosition": "He is now with Korea Real Estate Board (한국부동산원)"
},
{
"ko": "정중화",
"en": "Joong-Hwa Jung",
"degree": "PhD",
"graduatedAt": "2025-02",
"currentPosition": "He is now with Lychee AI Coding Academy (리치AI코딩학원) as CEO"
},
{
"ko": "임도현",
"en": "Dohyeon Lim",
"degree": "MS",
"graduatedAt": "2025-02",
"major": "Computer Science and Engineering",
"currentPosition": "He is now with TakenSoft (테이큰소프트)"
},
{
"ko": "김소용",
"en": "So-Yong Kim",
"degree": "PhD",
"graduatedAt": "2024-08",
"currentPosition": "He is now with Catholic University of Leuven (UCLouvain) in Belgium"
},
{
"ko": "김민지",
"en": "Min-Ji Kim",
"degree": "MS",
"graduatedAt": "2024-02",
"currentPosition": "She is now with LG Electronics"
},
{
"ko": "안은지",
"en": "Eun-Ji Ahn",
"degree": "MS",
"graduatedAt": "2024-02",
"currentPosition": "S is now with National Security Research Institute (국가보안연구소)"
},
{
"ko": "오동규",
"en": "Dong-Kyu Oh",
"degree": "MS",
"graduatedAt": "2024-02",
"major": "Industrial Engineering",
"currentPosition": "He is now with Human-Plus (휴먼플러스)"
},
{
"ko": "김재성",
"en": "Jae-Seong Kim",
"degree": "MS",
"graduatedAt": "2023-08",
"major": "Information Science",
"currentPosition": "He is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "최동규",
"en": "Dong-Kyu Choi",
"degree": "PhD",
"graduatedAt": "2023-02",
"currentPosition": "He is now with ISL in KNU"
},
{
"ko": "최진원",
"en": "Jin-Won Choi",
"degree": "MS",
"graduatedAt": "2023-02",
"major": "Information Science",
"currentPosition": "He is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "김지은",
"en": "Ji-Eun Kim",
"degree": "MS",
"graduatedAt": "2023-02",
"major": "Information Science",
"currentPosition": "She is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "김철민",
"en": "Cheol-Min Kim",
"degree": "PhD",
"graduatedAt": "2022-08",
"currentPosition": "He is now with KETI (한국전자기술연구원)"
},
{
"ko": "김경식",
"en": "Kyung-Sik Kim",
"degree": "MS",
"graduatedAt": "2022-02",
"currentPosition": "He is now with Hyundai Autoever (현대오토에버)"
},
{
"ko": "김근수",
"en": "Keun-Soo Kim",
"degree": "MS",
"graduatedAt": "2022-02",
"currentPosition": "He is now with Shinhan Bank (신한은행)"
},
{
"ko": "정성우",
"en": "Seong-Woo Jeong",
"degree": "MS",
"graduatedAt": "2022-02",
"major": "Information Science",
"currentPosition": "He is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "최민철",
"en": "Min-Cheol Choi",
"degree": "MS",
"graduatedAt": "2022-02",
"major": "Information Science",
"currentPosition": "He is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "장준희",
"en": "Jun-Hee Jang",
"degree": "MS",
"graduatedAt": "2021-08",
"major": "Computer Science and Engineering",
"currentPosition": "He is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "Muhammad Hafidh Firmansyah",
"en": "Muhammad Hafidh Firmansyah",
"degree": "MS",
"graduatedAt": "2021-08",
"currentPosition": "He is now with State Polytechnic University of Jember in Indonesia"
},
{
"ko": "장강민",
"en": "Kang-Min Jang",
"degree": "MS",
"graduatedAt": "2021-02",
"major": "Information Science",
"currentPosition": "He is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "이홍근",
"en": "Hong-Keun Lee",
"degree": "MS",
"graduatedAt": "2021-02",
"major": "Information Science",
"currentPosition": "He is now with NIA (한국지능정보사회진흥원)"
},
{
"ko": "남혜빈",
"en": "Hyebeen Nam",
"degree": "MS",
"graduatedAt": "2021-02",
"currentPosition": "She is now with ISL in KNU"
},
{
"ko": "최낙중",
"en": "Nak-Jung Choi",
"degree": "PhD",
"graduatedAt": "2020-02",
"currentPosition": "He is now with Agency for Defense Development (국방과학연구소)"
},
{
"ko": "정민우",
"en": "Min-Woo Jung",
"degree": "MS",
"graduatedAt": "2019-02",
"currentPosition": "He is now with LG Electronics (LG전자)"
},
{
"ko": "강형우",
"en": "Hyung-Woo Kang",
"degree": "PhD",
"graduatedAt": "2018-08",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "최예찬",
"en": "Ye-Chan Choi",
"degree": "MS",
"graduatedAt": "2018-02",
"currentPosition": "He is now with LG-CNS"
},
{
"ko": "최상일",
"en": "Sang-Il Choi",
"degree": "PhD",
"graduatedAt": "2017-02",
"currentPosition": "He is now with Daegu Catholic University (대구가톨릭대학교) as a professor"
},
{
"ko": "박진호",
"en": "Jin-Ho Park",
"degree": "MS",
"graduatedAt": "2016-08",
"currentPosition": "He is now with BiThumb (빗썸코리아)"
},
{
"ko": "석성윤",
"en": "Sung-Yoon Seok",
"degree": "MS",
"graduatedAt": "2016-08",
"major": "Samsung Electronics Program",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "김진규",
"en": "Jin-Kyu Kim",
"degree": "MS",
"graduatedAt": "2016-08",
"major": "Samsung Electronics Program",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "김재철",
"en": "Jae-Cheol Kim",
"degree": "MS",
"graduatedAt": "2016-08",
"major": "Samsung Electronics Program",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "김지인",
"en": "Ji-In Kim",
"degree": "PhD",
"graduatedAt": "2016-02",
"currentPosition": "He is now with FAM Tech. (팸텍) as CEO"
},
{
"ko": "김우주",
"en": "Woo-Ju Kim",
"degree": "MS",
"graduatedAt": "2016-02",
"currentPosition": "He is now with ZCube (지큐브)"
},
{
"ko": "박정섭",
"en": "Jung-Sub Park",
"degree": "MS",
"graduatedAt": "2015-08",
"major": "Samsung Electronics Program",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "최종명",
"en": "Jong-Myoung Choi",
"degree": "MS",
"graduatedAt": "2015-02",
"currentPosition": "He is now with NP Communications"
},
{
"ko": "이종관",
"en": "Jong-Kwan Lee",
"degree": "MS",
"graduatedAt": "2014-02",
"major": "Samsung Electronics Program",
"currentPosition": "He is now with Hanwha Ocean (한화오션)"
},
{
"ko": "이상헌",
"en": "Sang-Hun Lee",
"degree": "MS",
"graduatedAt": "2014-02",
"currentPosition": "He is now with Inno Wireless"
},
{
"ko": "민경욱",
"en": "Kyeong-Wook Min",
"degree": "MS",
"graduatedAt": "2013-02",
"major": "Samsung Electronics Program",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "김상헌",
"en": "Sang-Heon Kim",
"degree": "MS",
"graduatedAt": "2013-02",
"major": "Samsung Electronics Program",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "Moneeb Gohar",
"en": "Moneeb Gohar",
"degree": "PhD",
"graduatedAt": "2012-08",
"currentPosition": "He is now with Department of Computer Science, Bahria University (at Islamabad) in Pakistan"
},
{
"ko": "박재완",
"en": "Jae-Wan Park",
"degree": "MS",
"graduatedAt": "2012-02",
"currentPosition": "He is now with Ministry of Justice (Immigration Information Center, 법무부)"
},
{
"ko": "이재경",
"en": "Jae-Kyoung Lee",
"degree": "MS",
"graduatedAt": "2012-02",
"currentPosition": "She is now with Korea Transportation Satefy Authority (한국교통안전공단)"
},
{
"ko": "하원기",
"en": "Won-Ki Ha",
"degree": "MS",
"graduatedAt": "2012-02",
"major": "Samsung Electronics Program",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "김근희",
"en": "Keun-Hee Kim",
"degree": "MS",
"graduatedAt": "2012-02",
"major": "Samsung Electronics Program",
"currentPosition": "She is now with Samsung Electronics (삼성전자)"
},
{
"ko": "권순홍",
"en": "Soon-Hong Kwon",
"degree": "MS",
"graduatedAt": "2010-02",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "김동필",
"en": "Dong-Phil Kim",
"degree": "PhD",
"graduatedAt": "2009-02",
"currentPosition": "He is now with National Security Research Institute (국가보안연구소)"
},
{
"ko": "최린",
"en": "Lin Cui",
"degree": "PhD",
"graduatedAt": "2009-02",
"currentPosition": "He is now with Tianjin University of Technology and Education in China"
},
{
"ko": "이동화",
"en": "Dong-Hwa Lee",
"degree": "MS",
"graduatedAt": "2009-02",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
},
{
"ko": "박재성",
"en": "Jae-Sung Park",
"degree": "MS",
"graduatedAt": "2008-08",
"currentPosition": "He is now with Gom&Company (곰앤컴퍼니)"
},
{
"ko": "주수경",
"en": "Su-Kyoung Ju",
"degree": "MS",
"graduatedAt": "2008-02",
"currentPosition": "She is now with Youngjin Univ. (영진전문대학교)"
},
{
"ko": "윤성식",
"en": "Sung-Shik Yoon",
"degree": "MS",
"graduatedAt": "2007-08",
"currentPosition": "He is now with Jo-Il Textile Processing Company (조일가공) as CEO"
},
{
"ko": "김상태",
"en": "Sang-Tae Kim",
"degree": "MS",
"graduatedAt": "2007-02",
"currentPosition": "He is now with LG Electronics (LG전자)"
},
{
"ko": "하종식",
"en": "Jong-Shik Ha",
"degree": "MS",
"graduatedAt": "2007-02",
"currentPosition": "He is now with Samsung Electronics (삼성전자)"
}
];
File diff suppressed because it is too large Load Diff
+387
View File
@@ -0,0 +1,387 @@
// AUTO-GENERATED by scripts/extract/generate_all.py — DO NOT EDIT BY HAND
import { StandardsBody } from "./types";
export const standardsBodies: StandardsBody[] = [
{
"org": "IEC TC100",
"full": "Multimedia Systems and Equipment",
"scope": "international",
"period": "2018 ~ Present",
"role": "Convenor",
"projects": [
{
"wg": "WG12",
"name": "Multimedia Systems and Equipment for Metaverse (IEC 63614)",
"documents": [
{
"title": "Multimedia Systems and Equipment for Metaverse - Part 1: Genaral",
"ref": "IEC TR 63614-1 (May 2026)",
"status": "TR",
"publishedAt": "May 2026"
},
{
"title": "Multimedia Systems and Equipment for Metaverse - Part 2: Classification",
"ref": "IEC TS 63614-2 (May 2026)",
"status": "TS",
"publishedAt": "May 2026"
},
{
"title": "Multimedia Systems and Equipment for Metaverse - Part 3: Gap Analysis",
"ref": "IEC TR 63614-3 (March 2026)",
"status": "TR",
"publishedAt": "March 2026"
},
{
"title": "Multimedia Systems and Equipment for Metaverse - Part 4: AI Use Cases",
"ref": "IEC WDTR 63614-4 (In Progress)",
"status": "InProgress"
}
]
},
{
"wg": "WG11(Convenor)",
"name": "User's QoE for Multimedia Conference Services (IEC 63478)",
"documents": [
{
"title": "User's QoE for Multimedia Conference Services - Part 1: General",
"ref": "IEC TR 63478-1 (November 2023)",
"status": "TR",
"publishedAt": "November 2023"
},
{
"title": "User's QoE for Multimedia Conference Services - Part 2: Requirments",
"ref": "IEC IS 63478-2 (October 2025)",
"status": "IS",
"publishedAt": "October 2025"
},
{
"title": "User's QoE for Multimedia Conference Services - Part 3: Measurement Methods",
"ref": "IEC CDV 63478-3 (In Progress)",
"status": "InProgress"
}
]
},
{
"wg": "WG30(TA17)",
"name": "Infotainment Services for Public Vehicles (IEC 63479)",
"documents": [
{
"title": "Infotainment Services for Public Vehicles (PVIS) - Part 1: General",
"ref": "IEC TR 63479-1 (November 2023)",
"status": "TR",
"publishedAt": "November 2023"
},
{
"title": "Infotainment Services for Public Vehicles (PVIS) - Part 2: Requirements",
"ref": "IEC IS 63479-2 (February 2026)",
"status": "IS",
"publishedAt": "February 2026"
},
{
"title": "Infotainment Services for Public Vehicles (PVIS) - Part 3: Framework",
"ref": "IEC IS 63479-3 (January 2026)",
"status": "IS",
"publishedAt": "January 2026"
}
]
},
{
"wg": "WG30(TA17)",
"name": "Configurable Car Infotainment Services (IEC 63246)",
"documents": [
{
"title": "Configurable Car Infotainment Services (CCIS) - Part 1: General",
"ref": "IEC 63246-1 (August 2021)",
"status": "IS",
"publishedAt": "August 2021"
},
{
"title": "Configurable Car Infotainment Services (CCIS) - Part 2: Requirements",
"ref": "IEC 63246-2 (January 2022)",
"status": "IS",
"publishedAt": "January 2022"
},
{
"title": "Configurable Car Infotainment Services (CCIS) - Part 3: Framework",
"ref": "IEC 63246-3 (January 2022)",
"status": "IS",
"publishedAt": "January 2022"
},
{
"title": "Configurable Car Infotainment Services (CCIS) - Part 4: Protocol",
"ref": "IEC TR 63246-4 (December 2022)",
"status": "TR",
"publishedAt": "December 2022"
}
]
}
]
},
{
"org": "ISO/IEC JTC1/SC41",
"full": "Internet of Things and Digital Twin",
"scope": "international",
"period": "2020 ~ Present",
"projects": [
{
"wg": "WG",
"name": "(WG5) IoT-based Management of Tangible Cultural Heritage Assets (ISO/IEC TR 30189)",
"documents": [
{
"title": "Part 1: Framework",
"ref": "ISO/IEC TR 30189-1 (March 2025)",
"status": "TR",
"publishedAt": "March 2025"
},
{
"title": "Part 2: Use Cases",
"ref": "ISO/IEC CDTR 30189-2 (In Progress)",
"status": "InProgress"
}
]
}
]
},
{
"org": "ITU-T SG20",
"full": "IoT Services based on VLC",
"scope": "international",
"period": "2018 ~ 2020",
"projects": [
{
"wg": "Main",
"name": "IoT Services based on VLC",
"documents": [
{
"title": "Framework of IoT Services based on Visible Light Communications (VLC)",
"ref": "ITU-T Recommendation Y.4465 (January 2020)",
"status": "IS",
"publishedAt": "January 2020"
},
{
"title": "Functional Architecture for IoT Services based on VLC",
"ref": "ITU-T Recommendation Y.4474 (August 2020)",
"status": "IS",
"publishedAt": "August 2020"
}
]
}
]
},
{
"org": "TTA/PG425",
"full": "가시광 통신 기반 사물인터넷 서비스",
"scope": "domestic",
"period": "2018 ~ 2020",
"projects": [
{
"wg": "Main",
"name": "가시광 통신 기반 사물인터넷 서비스",
"documents": [
{
"title": "가시광 통신 기반 사물인터넷 서비스 - 제 1 부: 네트워크 모델 및 요구사항",
"ref": "TTAK.KO-10.1158-part1 (2019년 12월)",
"status": "IS",
"publishedAt": "2019년 12월"
},
{
"title": "가시광 통신 기반 사물인터넷 서비스 - 제 2 부: 프레임워크",
"ref": "TTAK.KO-10.1158-part2 (2020년 12월)",
"status": "IS",
"publishedAt": "2020년 12월"
},
{
"title": "가시광 통신 기반 사물인터넷 서비스 - 제 3 부: 프로토콜",
"ref": "TTAK.KO-10.1158-part3 (2020년 12월)",
"status": "IS",
"publishedAt": "2020년 12월"
}
]
}
]
},
{
"org": "ITU-T SG13",
"full": "Mobility Management",
"scope": "international",
"period": "2002 ~ 2012",
"projects": [
{
"wg": "Main",
"name": "Mobility Management",
"documents": [
{
"title": "NNI Mobility Management Requirements for SBI2K",
"ref": "ITU-T Supplement to Recommendation Q.Sup52 (December 2004)",
"status": "IS",
"publishedAt": "December 2004"
},
{
"title": "Mobility Management Requirements for Next-Generation Networks",
"ref": "ITU-T Recommendation Q.1706/Y.2801 (July 2006)",
"status": "IS",
"publishedAt": "July 2006"
},
{
"title": "Framework of IPv6 Multi-homing for NGN",
"ref": "ITU-T Recommendation Y.2052 (Feb. 2008)",
"status": "IS",
"publishedAt": "Feb. 2008"
},
{
"title": "Generic Framework of Mobility Management for Next-Generation Networks",
"ref": "ITU-T Recommendation Q.1707/Y.2804 (Feb. 2008)",
"status": "IS",
"publishedAt": "Feb. 2008"
},
{
"title": "Framework of Location Management for Next-Generation Networks",
"ref": "ITU-T Recommendation Q.1708/Y.2805 (October 2008)",
"status": "IS",
"publishedAt": "October 2008"
},
{
"title": "Framework of Handover Control for Next-Generation Networks",
"ref": "ITU-T Recommendation Q.1709/Y.2806 (October 2008)",
"status": "IS",
"publishedAt": "October 2008"
},
{
"title": "Framework of Mobility Management in Service Stratum for NGN",
"ref": "ITU-T Recommendation Y.2809 (November 2011)",
"status": "IS",
"publishedAt": "November 2011"
}
]
}
]
},
{
"org": "ISO/IEC JTC1/SC6",
"full": "WG7: Network and Transport",
"scope": "international",
"period": "2000 ~ 2014",
"projects": [
{
"wg": "Enhanced Communication Transport Protocol (ECTP)",
"name": "ISO/IEC 14476",
"documents": [
{
"title": "ECTP-1: Specification of Simplex Multicast Transport",
"ref": "ITU-T Recommendation X.606 (October 2001) ISO/IEC IS 14476-1 (April 2002)",
"status": "IS",
"publishedAt": "October 2001"
},
{
"title": "ECTP-2: Specification of QoS Management for Simplex Multicast Transport",
"ref": "ITU-T Recommendation X.606.1 (February 2003) ISO/IEC IS 14476-2 (June 2003)",
"status": "IS",
"publishedAt": "February 2003"
},
{
"title": "ECTP-3: Specification of Duplex Multicast Transport",
"ref": "ITU-T Recommendation X.607 (February 2007) ISO/IEC IS 14476-3 (August 2008)",
"status": "IS",
"publishedAt": "February 2007"
},
{
"title": "ECTP-4: Specification of QoS Management for Duplex Multicast Transport",
"ref": "ITU-T Recommendation X.607.1 (November 2008) ISO/IEC IS 14476-4 (April 2010)",
"status": "IS",
"publishedAt": "November 2008"
},
{
"title": "ECTP-5: Specification of N-plex Multicast Transport",
"ref": "ITU-T Recommendation X.608 (February 2007) ISO/IEC IS 14476-5 (August 2008)",
"status": "IS",
"publishedAt": "February 2007"
},
{
"title": "ECTP-6: Specification of QoS Management for N-plex Multicast Transport",
"ref": "ITU-T Recommendation X.608.1 (November 2008) ISO/IEC IS 14476-6 (April 2010)",
"status": "IS",
"publishedAt": "November 2008"
}
]
},
{
"wg": "Relayed Multicast Protocol (RMCP)",
"name": "ISO/IEC 16512",
"documents": [
{
"title": "RMCP-1: Framework",
"ref": "ITU-T Recommendation X.603 (April 2004) ISO/IEC IS 16512-1",
"status": "IS",
"publishedAt": "April 2004"
},
{
"title": "RMCP-2: Specification of Simplex Group Applications",
"ref": "ITU-T Recommendation X.603.1 (February 2007) ISO/IEC IS 16512-2",
"status": "IS",
"publishedAt": "February 2007"
},
{
"title": "RMCP-3: Specification of N-plex Group Applications",
"ref": "ITU-T Recommendation X.603.2 (September 2010) ISO/IEC IS 16512-3",
"status": "IS",
"publishedAt": "September 2010"
}
]
},
{
"wg": "Mobile Multicast Communications (MMC)",
"name": "ISO/IEC 24793",
"documents": [
{
"title": "MMC-1: MMC Framework",
"ref": "ITU-T Recommendation X.604 (March 2010) ISO/IEC IS 24793-1",
"status": "IS",
"publishedAt": "March 2010"
},
{
"title": "MMC-2: MMC Protocol over Native IP Multicast Networks",
"ref": "ITU-T Recommendation X.604.1 (March 2010) ISO/IEC IS 24793-2",
"status": "IS",
"publishedAt": "March 2010"
},
{
"title": "MMC-3: MMC Protocol over Overlay Multicast Networks",
"ref": "ITU-T Recommendation X.604.2 (September 2010) ISO/IEC IS 24793-3",
"status": "IS",
"publishedAt": "September 2010"
}
]
},
{
"wg": "Future Network",
"name": "Problem Statement and Requirements (FN-PSR): ISO/IEC TR 29181",
"documents": [
{
"title": "Part 1: Overall Aspects",
"ref": "ISO/IEC TR 29181-1 (September 2012)",
"status": "TR",
"publishedAt": "September 2012"
},
{
"title": "Part 2: Naming and Addressing",
"ref": "ISO/IEC TR 29181-2 (December 2014)",
"status": "TR",
"publishedAt": "December 2014"
},
{
"title": "Part 3: Switching and Routing",
"ref": "ISO/IEC TR 29181-3 (April 2013)",
"status": "TR",
"publishedAt": "April 2013"
},
{
"title": "Part 4: Mobility",
"ref": "ISO/IEC TR 29181-4 (December 2013)",
"status": "TR",
"publishedAt": "December 2013"
}
]
}
]
}
];
+83
View File
@@ -0,0 +1,83 @@
// Types definition for ANL Lab website content
export type Degree = "Professor" | "PhD" | "PhDCandidate" | "PhDStudent" | "MSCandidate" | "MSStudent";
export interface Member {
ko: string;
en: string;
degree: Degree;
affiliation?: string;
}
export interface Alumnus {
ko: string;
en: string;
degree: "PhD" | "MS";
graduatedAt: string; // ISO 8601 YYYY-MM
major?: string;
currentPosition?: string;
}
export type PubCategory =
| "intl-conf"
| "intl-journal-conf"
| "domestic-journal-conf"
| "patent";
export interface Publication {
category: PubCategory;
title: string;
authors?: string; // Optional, set to undefined for papers without authors
venue?: string;
volume?: string;
publishedAt: string; // ISO 8601 YYYY-MM or YYYY-MM-DD
kci?: boolean;
doi?: string;
}
export interface Patent {
category: "patent";
title: string;
inventors: string;
applicationNo: string;
applicationAt: string;
registrationNo?: string;
registrationAt?: string;
country: string;
publishedAt: string;
}
export interface Course {
code: string;
en: string;
note?: string;
}
export interface Semester {
term: "Spring" | "Fall";
year: number;
courses: Course[];
}
export type DocStatus = "IS" | "TS" | "TR" | "CDV" | "WDTR" | "InProgress";
export interface StandardDoc {
title: string;
ref: string;
status: DocStatus;
publishedAt?: string;
}
export interface StandardProject {
wg: string;
name: string;
documents: StandardDoc[];
}
export interface StandardsBody {
org: string;
full: string;
scope: "international" | "domestic";
period: string;
role?: string;
projects: StandardProject[];
}
+9
View File
@@ -1,6 +1,15 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
async redirects() {
return [
{
source: "/intro",
destination: "/",
permanent: true, // 308 permanent redirect (H-11 / IA-02)
},
];
},
};
module.exports = nextConfig;
@@ -0,0 +1,421 @@
#!/usr/bin/env python3
import os
import re
import json
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
ISL_DIR = os.path.join(BASE_DIR, "..", "ISL-2026")
CONTENT_DIR = os.path.join(BASE_DIR, "content")
def read_file(filename):
path = os.path.join(ISL_DIR, filename)
with open(path, "r", encoding="utf-8-sig") as f:
return f.read()
def parse_members():
html = read_file("member.html")
parts = re.split(r'<H2>\s*Alumni.*?</H2>', html, flags=re.S | re.I)
active_html = parts[0]
alumni_html = parts[1] if len(parts) > 1 else ""
degree_map = {
"Professor": "Professor",
"Ph. D.": "PhD",
"Ph.D.": "PhD",
"Ph. D. Candidate": "PhDCandidate",
"Ph.D. Candidate": "PhDCandidate",
"Ph. D. Student": "PhDStudent",
"Ph.D. Student": "PhDStudent",
"M. S. Candidate": "MSCandidate",
"M.S. Candidate": "MSCandidate",
"M. S. Student": "MSStudent",
"M.S. Student": "MSStudent",
}
# Active members
active_members = []
active_items = re.findall(r'<LI><H4>(.*?)</H4>', active_html, flags=re.S | re.I)
for item in active_items:
clean_item = re.sub(r'<a.*?>.*?</a>', '', item, flags=re.I)
clean_item = re.sub(r'<.*?>', '', clean_item)
clean_item = clean_item.strip().replace('\n', ' ')
if not clean_item:
continue
m = re.search(r'^(.*?)\s*\((.*?),\s*(.*?)\)(?:\s*with\s*(.*))?$', clean_item)
if m:
en = m.group(1).strip()
ko = m.group(2).strip()
deg_str = m.group(3).strip()
aff = m.group(4).strip() if m.group(4) else None
else:
# Case like Hoang Anh Dang (M. S. Student)
m2 = re.search(r'^(.*?)\s*\((.*?)\)(?:\s*with\s*(.*))?$', clean_item)
if m2:
en = m2.group(1).strip()
ko = en
deg_str = m2.group(2).strip()
aff = m2.group(3).strip() if m2.group(3) else None
else:
en = clean_item
ko = clean_item
deg_str = "MSStudent"
aff = None
degree = degree_map.get(deg_str, "MSStudent")
mem = {"ko": ko, "en": en, "degree": degree}
if aff:
mem["affiliation"] = aff
active_members.append(mem)
# Alumni
alumni = []
alumni_items = re.findall(r'<LI><H4>(.*?)</H4>', alumni_html, flags=re.S | re.I)
if len(alumni_items) < 60:
alumni_items = re.findall(r'<LI>(.*?)(?=<LI>|<OL>|</OL>|$)', alumni_html, flags=re.S | re.I)
month_map = {"January":"01","February":"02","March":"03","April":"04","May":"05","June":"06","July":"07","August":"08","September":"09","October":"10","November":"11","December":"12"}
for item in alumni_items:
clean = re.sub(r'<.*?>', '\n', item).strip()
lines = [l.strip() for l in clean.split('\n') if l.strip()]
if not lines:
continue
first_line = lines[0]
if "Alumni" in first_line:
continue
m = re.search(r'^(.*?)\s*\((?:(.*?),\s*)?(Ph\.\s*D\.|Ph\.D\.|M\.\s*S\.|M\.S\.)\s+([A-Za-z]+\s+\d{4})', first_line)
if not m:
m = re.search(r'^(.*?)\s*\((?:(.*?),\s*)?(Ph\.\s*D\.|Ph\.D\.|M\.\s*S\.|M\.S\.)', first_line)
if m:
en = m.group(1).strip()
ko = m.group(2).strip() if m.group(2) else en
deg_raw = m.group(3).strip()
date_raw = m.group(4).strip() if len(m.groups()) >= 4 and m.group(4) else "August 2026"
major = None
if " in " in first_line:
m_maj = re.search(r'\s+in\s+([A-Za-z\s]+)', first_line)
if m_maj: major = m_maj.group(1).strip()
degree = "PhD" if "Ph" in deg_raw else "MS"
parts = date_raw.split()
grad_date = f"{parts[1]}-{month_map.get(parts[0], '01')}" if len(parts)==2 else "2026-01"
cur_pos = " ".join(lines[1:]) if len(lines) > 1 else None
alum = {
"ko": ko,
"en": en,
"degree": degree,
"graduatedAt": grad_date,
}
if major: alum["major"] = major
if cur_pos: alum["currentPosition"] = cur_pos
alumni.append(alum)
return active_members, alumni
def parse_publications():
intl_html = read_file("paper-international.html")
dom_html = read_file("paper-domestic.html")
pat_html = read_file("patent.html")
month_map = {"January":"01","February":"02","March":"03","April":"04","May":"05","June":"06","July":"07","August":"08","September":"09","October":"10","November":"11","December":"12"}
intl_pubs = []
intl_items = re.findall(r'<LI>(.*?)</LI>', intl_html, flags=re.S | re.I)
for item in intl_items:
m_title = re.search(r'<U>\s*"(.*?)"\s*<br/?>\s*</U>', item, flags=re.S | re.I)
if not m_title:
m_title = re.search(r'<U>\s*"(.*?)"\s*</U>', item, flags=re.S | re.I)
title = m_title.group(1).replace('\n', ' ').strip() if m_title else ""
m_venue = re.search(r'<I>\s*(.*?)\s*</I>', item, flags=re.S | re.I)
venue = m_venue.group(1).replace('\n', ' ').strip() if m_venue else ""
rest = item[m_venue.end():] if m_venue else item
rest_clean = re.sub(r'<.*?>', '', rest).replace('\n', ' ').strip()
rest_clean = re.sub(r'^\s*,\s*', '', rest_clean)
m_date = re.search(r'([A-Za-z]+)\s+(\d{4})', rest_clean)
pub_date = "2026-01"
if m_date:
mo, yr = m_date.group(1), m_date.group(2)
if mo in month_map:
pub_date = f"{yr}-{month_map[mo]}"
intl_pubs.append({
"category": "intl-journal-conf",
"title": title,
"venue": venue,
"volume": rest_clean,
"publishedAt": pub_date
})
dom_pubs = []
dom_items = re.findall(r'<LI>(.*?)</LI>', dom_html, flags=re.S | re.I)
for item in dom_items:
m_title = re.search(r'<U>\s*"(.*?)"\s*<br/?>\s*</U>', item, flags=re.S | re.I)
if not m_title:
m_title = re.search(r'<U>\s*"(.*?)"\s*</U>', item, flags=re.S | re.I)
title = m_title.group(1).replace('\n', ' ').strip() if m_title else ""
m_venue = re.search(r'<I>\s*(.*?)\s*</I>', item, flags=re.S | re.I)
venue = m_venue.group(1).replace('\n', ' ').strip() if m_venue else ""
rest = item[m_venue.end():] if m_venue else item
rest_clean = re.sub(r'<.*?>', '', rest).replace('\n', ' ').strip()
rest_clean = re.sub(r'^\s*,\s*', '', rest_clean)
is_kci = "(KCI)" in item or "(KCI)" in rest_clean
m_date = re.search(r'(\d{4})년\s*(\d{1,2})월', rest_clean)
if m_date:
pub_date = f"{m_date.group(1)}-{int(m_date.group(2)):02d}"
else:
pub_date = "2026-01"
dom_pubs.append({
"category": "domestic-journal-conf",
"title": title,
"venue": venue,
"volume": rest_clean,
"publishedAt": pub_date,
"kci": is_kci
})
patents = []
pat_items = re.findall(r'<LI>(.*?)</LI>', pat_html, flags=re.S | re.I)
for item in pat_items:
clean = re.sub(r'<.*?>', '\n', item)
lines = [l.strip() for l in clean.split('\n') if l.strip()]
if not lines:
continue
title = lines[0]
inventors = ""
app_no = ""
app_date = ""
reg_no = None
reg_date = None
country = "한국"
for l in lines[1:]:
if l.startswith("발명자:"):
inventors = l.replace("발명자:", "").strip()
elif l.startswith("출원번호:"):
m = re.search(r'출원번호:\s*([\d-]+)\s*\((.*?),\s*([\d.]+)\)', l)
if m:
app_no = m.group(1)
country = m.group(2)
app_date = m.group(3).replace('.', '-')
else:
app_no = l.replace("출원번호:", "").strip()
elif l.startswith("등록번호:"):
m = re.search(r'등록번호:\s*([\d-]+)\s*\((.*?),\s*([\d.]+)\)', l)
if m:
reg_no = m.group(1)
reg_date = m.group(3).replace('.', '-')
else:
reg_no = l.replace("등록번호:", "").strip()
pub_date = app_date[:7] if app_date else "2026-01"
patents.append({
"category": "patent",
"title": title,
"inventors": inventors,
"applicationNo": app_no,
"applicationAt": app_date,
"registrationNo": reg_no,
"registrationAt": reg_date,
"country": country,
"publishedAt": pub_date
})
return intl_pubs, dom_pubs, patents
def parse_lectures():
html = read_file("lecture.html")
semesters = []
sections = re.split(r'<H1 ALIGN="CENTER">(.*?)</H1>', html, flags=re.I)
for i in range(1, len(sections), 2):
term_str = sections[i].strip()
body = sections[i+1]
parts = term_str.split()
if len(parts) != 2:
continue
term = parts[0]
year = int(parts[1])
courses = []
c_items = re.findall(r'<H3>(.*?)(?:</H3>|<BR>|$)', body, flags=re.S | re.I)
for item in c_items:
clean = re.sub(r'<.*?>', '', item).strip()
if not clean:
continue
if "No Class" in clean:
courses.append({"code": "SABBATICAL", "en": "No Class (Sabbatical)", "note": "Sabbatical"})
else:
m = re.search(r'^(.*?)\s*\((.*?)\)$', clean)
if m:
courses.append({"code": m.group(2).strip(), "en": m.group(1).strip()})
else:
courses.append({"code": "COMP", "en": clean})
semesters.append({
"term": term,
"year": year,
"courses": courses
})
return semesters
def parse_standards():
html = read_file("standard.html")
bodies = []
sections = re.split(r'<H3>(.*?)</H3>', html, flags=re.I)
for i in range(1, len(sections), 2):
header = sections[i].strip()
body = sections[i+1]
m_head = re.search(r'^(.*?)\s*\((.*?)\):\s*(.*)$', header)
if not m_head:
continue
org = m_head.group(1).strip()
full = m_head.group(2).strip()
period = m_head.group(3).strip()
scope = "domestic" if "TTA" in org else "international"
role = "Convenor" if "Convenor" in header or "Convenor" in body else None
projects = []
# If 'o ' exists, split by 'o '
if re.search(r'^\s*o\s+', body, flags=re.M):
proj_blocks = re.split(r'\s*o\s+', body)
for proj_b in proj_blocks:
if not proj_b.strip():
continue
lines = proj_b.strip().split('<OL>')
p_head = lines[0].replace('<BR>', '').strip()
m_proj = re.search(r'^(.*?):\s*(.*)$', p_head)
wg = m_proj.group(1).strip() if m_proj else "WG"
p_name = m_proj.group(2).strip() if m_proj else p_head
docs = []
if len(lines) > 1:
doc_items = re.findall(r'<LI>(.*?)</LI>', lines[1], flags=re.S | re.I)
for d_item in doc_items:
d_clean = re.sub(r'<.*?>', '\n', d_item)
d_lines = [l.strip() for l in d_clean.split('\n') if l.strip()]
if not d_lines:
continue
d_title = d_lines[0].strip('" ')
d_rest = " ".join(d_lines[1:]) if len(d_lines) > 1 else ""
status = "IS"
if "In Progress" in d_rest: status = "InProgress"
elif "WDTR" in d_rest or "CDTR" in d_rest: status = "WDTR"
elif "CDV" in d_rest: status = "CDV"
elif "TR" in d_rest: status = "TR"
elif "TS" in d_rest: status = "TS"
m_date = re.search(r'\((.*?)\)', d_rest)
pub_date = m_date.group(1) if m_date and "In Progress" not in m_date.group(1) else None
docs.append({
"title": d_title,
"ref": d_rest,
"status": status,
"publishedAt": pub_date
})
projects.append({
"wg": wg,
"name": p_name,
"documents": docs
})
else:
# Single project body
doc_items = re.findall(r'<LI>(.*?)</LI>', body, flags=re.S | re.I)
docs = []
for d_item in doc_items:
d_clean = re.sub(r'<.*?>', '\n', d_item)
d_lines = [l.strip() for l in d_clean.split('\n') if l.strip()]
if not d_lines:
continue
d_title = d_lines[0].strip('" ')
d_rest = " ".join(d_lines[1:]) if len(d_lines) > 1 else ""
status = "IS"
if "In Progress" in d_rest: status = "InProgress"
elif "WDTR" in d_rest or "CDTR" in d_rest: status = "WDTR"
elif "CDV" in d_rest: status = "CDV"
elif "TR" in d_rest: status = "TR"
elif "TS" in d_rest: status = "TS"
m_date = re.search(r'\((.*?)\)', d_rest)
pub_date = m_date.group(1) if m_date and "In Progress" not in m_date.group(1) else None
docs.append({
"title": d_title,
"ref": d_rest,
"status": status,
"publishedAt": pub_date
})
projects.append({
"wg": "Main",
"name": full,
"documents": docs
})
bodies.append({
"org": org,
"full": full,
"scope": scope,
"period": period,
"role": role,
"projects": projects
})
return bodies
def clean_dict(obj):
if isinstance(obj, dict):
return {k: clean_dict(v) for k, v in obj.items() if v is not None}
elif isinstance(obj, list):
return [clean_dict(v) for v in obj if v is not None]
return obj
def main():
active_m, alumni_m = parse_members()
intl_p, dom_p, pat_p = parse_publications()
semesters = parse_lectures()
bodies = parse_standards()
os.makedirs(CONTENT_DIR, exist_ok=True)
with open(os.path.join(CONTENT_DIR, "members.ts"), "w", encoding="utf-8") as f:
f.write('// AUTO-GENERATED by scripts/extract/generate_all.py — DO NOT EDIT BY HAND\n')
f.write('import { Member, Alumnus } from "./types";\n\n')
f.write(f'export const activeMembers: Member[] = {json.dumps(clean_dict(active_m), ensure_ascii=False, indent=2)};\n\n')
f.write(f'export const alumni: Alumnus[] = {json.dumps(clean_dict(alumni_m), ensure_ascii=False, indent=2)};\n')
with open(os.path.join(CONTENT_DIR, "publications.ts"), "w", encoding="utf-8") as f:
f.write('// AUTO-GENERATED by scripts/extract/generate_all.py — DO NOT EDIT BY HAND\n')
f.write('import { Publication, Patent } from "./types";\n\n')
all_pubs = intl_p + dom_p
f.write(f'export const publications: Publication[] = {json.dumps(clean_dict(all_pubs), ensure_ascii=False, indent=2)};\n\n')
f.write(f'export const patents: Patent[] = {json.dumps(clean_dict(pat_p), ensure_ascii=False, indent=2)};\n')
with open(os.path.join(CONTENT_DIR, "lectures.ts"), "w", encoding="utf-8") as f:
f.write('// AUTO-GENERATED by scripts/extract/generate_all.py — DO NOT EDIT BY HAND\n')
f.write('import { Semester } from "./types";\n\n')
f.write(f'export const semesters: Semester[] = {json.dumps(clean_dict(semesters), ensure_ascii=False, indent=2)};\n')
with open(os.path.join(CONTENT_DIR, "standards.ts"), "w", encoding="utf-8") as f:
f.write('// AUTO-GENERATED by scripts/extract/generate_all.py — DO NOT EDIT BY HAND\n')
f.write('import { StandardsBody } from "./types";\n\n')
f.write(f'export const standardsBodies: StandardsBody[] = {json.dumps(clean_dict(bodies), ensure_ascii=False, indent=2)};\n')
if __name__ == "__main__":
main()
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
import sys
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
CONTENT_DIR = os.path.join(BASE_DIR, "refer_landing_page", "content")
sys.path.insert(0, os.path.join(BASE_DIR, "refer_landing_page", "scripts", "extract"))
def verify():
# Import generated modules or json
from generate_all import parse_members, parse_publications, parse_lectures, parse_standards
active_m, alumni_m = parse_members()
intl_p, dom_p, pat_p = parse_publications()
semesters = parse_lectures()
bodies = parse_standards()
total_pubs = len(intl_p) + len(dom_p) + len(pat_p)
std_docs_count = sum(len(p["documents"]) for b in bodies for p in b["projects"])
print("=== DATA VERIFICATION GATE (AC-07 / AC-08) ===")
print(f"Active Members: {len(active_m)} (Expected: 16)")
print(f"Alumni: {len(alumni_m)} (Expected: 60)")
print(f"International Papers: {len(intl_p)} (Expected: 68)")
print(f"Domestic Papers: {len(dom_p)} (Expected: 80)")
print(f"Patents: {len(pat_p)} (Expected: 75)")
print(f"Total Publications: {total_pubs} (Expected: 223)")
print(f"Standard Bodies: {len(bodies)} (Expected: 6)")
print(f"Standard Documents: {std_docs_count} (Expected: ~55)")
errors = []
if len(active_m) != 16:
errors.append(f"Active Members count mismatch: got {len(active_m)}, expected 16")
if len(alumni_m) != 60:
errors.append(f"Alumni count mismatch: got {len(alumni_m)}, expected 60")
if len(intl_p) != 68:
errors.append(f"International Papers count mismatch: got {len(intl_p)}, expected 68")
if len(dom_p) != 80:
errors.append(f"Domestic Papers count mismatch: got {len(dom_p)}, expected 80")
if len(pat_p) != 75:
errors.append(f"Patents count mismatch: got {len(pat_p)}, expected 75")
if total_pubs != 223:
errors.append(f"Total Publications count mismatch: got {total_pubs}, expected 223")
if errors:
print("\n❌ VERIFICATION FAILED:")
for err in errors:
print(f" - {err}")
sys.exit(1)
else:
print("\n✅ ALL DATA VERIFICATION GATES PASSED CLEAN (Exit Code 0)")
sys.exit(0)
if __name__ == "__main__":
verify()