feat: implementasi Kodeva - sistem manajemen kursus coding

Fitur lengkap:
- Auth JWT + RBAC (Admin/Teacher) + halaman login
- Shell 3 kolom (left nav, topbar, right rail dashboard)
- CRUD siswa + follow up kanban + status calon/student/ex
- Dashboard: siswa aktif, kehadiran, bar sumber lead, perlu follow up
- Pembayaran prorata per pertemuan (cash/transfer/qris)
- Kelas, enrollment, generate sesi, kehadiran bulk
- Jurnal aktivitas + upload multi-foto
- Raport + placement test (tampil di detail siswa)
- Pengaturan & seed data contoh

Stack: Next.js 16, TypeScript, Tailwind v4, Prisma (SQLite), Recharts, Zod
This commit is contained in:
Amadea
2026-09-18 19:24:59 +07:00
commit 61ce9d7926
86 changed files with 13392 additions and 0 deletions
+329
View File
@@ -0,0 +1,329 @@
/**
* seed.example.ts — Contoh data Kodeva (Sistem Manajemen Kursus Coding)
* ---------------------------------------------------------------------
* Cara pakai:
* 1) Salin ke `prisma/seed.ts`
* 2) Tambahkan ke package.json → "prisma": { "seed": "tsx prisma/seed.ts" }
* 3) Jalankan: pnpm db:push && pnpm db:seed
*
* Login contoh:
* admin@kodeva.id / password123 (ADMIN)
* budi@kodeva.id / password123 (TEACHER)
* rina@kodeva.id / password123 (TEACHER)
*
* Catatan: cocok dengan skema di AGENTS.md (PostgreSQL).
*/
import { PrismaClient, AttendanceStatus, PaymentStatus, PlacementLevel } from "@prisma/client";
import bcrypt from "bcryptjs";
const prisma = new PrismaClient();
const BASE = new Date("2026-09-18T00:00:00.000Z");
const addDays = (n: number, from: Date = BASE) => new Date(from.getTime() + n * 86_400_000);
const addWeeks = (n: number, from: Date = BASE) => addDays(n * 7, from);
const PASS = bcrypt.hashSync("password123", 10);
const avatar = (seed: string) => `https://i.pravatar.cc/240?u=${encodeURIComponent(seed)}`;
const photo = (seed: string) => `https://picsum.photos/seed/${encodeURIComponent(seed)}/900/600`;
async function main() {
console.log("🌱 Seed Kodeva dimulai...");
// Bersihkan (urutan penting karena relasi)
await prisma.followUpActivity.deleteMany();
await prisma.followUp.deleteMany();
await prisma.placementScore.deleteMany();
await prisma.placementTest.deleteMany();
await prisma.reportScore.deleteMany();
await prisma.reportCard.deleteMany();
await prisma.journalStudent.deleteMany();
await prisma.journalPhoto.deleteMany();
await prisma.journal.deleteMany();
await prisma.payment.deleteMany();
await prisma.attendance.deleteMany();
await prisma.session.deleteMany();
await prisma.enrollment.deleteMany();
await prisma.student.deleteMany();
await prisma.class.deleteMany();
await prisma.user.deleteMany();
await prisma.setting.deleteMany();
// ─────────────────────────────────────────────────────────────
// 1. USERS (Admin + Teacher)
// ─────────────────────────────────────────────────────────────
const sari = await prisma.user.create({
data: {
name: "Sari Wulandari", email: "admin@kodeva.id", passwordHash: PASS,
role: "ADMIN", phone: "0811-2000-100", avatarUrl: avatar("sari"),
},
});
const budi = await prisma.user.create({
data: {
name: "Budi Santoso", email: "budi@kodeva.id", passwordHash: PASS,
role: "TEACHER", phone: "0812-3000-200", avatarUrl: avatar("budi"),
},
});
const rina = await prisma.user.create({
data: {
name: "Rina Kartika", email: "rina@kodeva.id", passwordHash: PASS,
role: "TEACHER", phone: "0813-4000-300", avatarUrl: avatar("rina"),
},
});
const ahmad = await prisma.user.create({
data: {
name: "Ahmad Fauzi", email: "ahmad@kodeva.id", passwordHash: PASS,
role: "TEACHER", phone: "0814-5000-400", avatarUrl: avatar("ahmad"),
},
});
// ─────────────────────────────────────────────────────────────
// 2. KELAS (konfigurasi kelas)
// pricePerMeeting = packagePrice / totalMeetings
// ─────────────────────────────────────────────────────────────
const classesData = [
{ code: "KOD-SCR-01", name: "Scratch Junior", level: "BEGINNER" as PlacementLevel, teacherId: rina.id, totalMeetings: 8, packagePrice: 1_200_000, pricePerMeeting: 150_000, capacity: 10, schedule: "Senin & Rabu 16:00-17:30", color: "#2AA9FF", description: "Belajar logika pemrograman lewat game visual Scratch." },
{ code: "KOD-PYT-01", name: "Python Dasar", level: "BEGINNER" as PlacementLevel, teacherId: budi.id, totalMeetings: 10, packagePrice: 2_000_000, pricePerMeeting: 200_000, capacity: 12, schedule: "Selasa & Kamis 17:00-18:30", color: "#7C5CFC", description: "Fondasi Python: variabel, logika, loop, dan fungsi." },
{ code: "KOD-WEB-01", name: "Web Dev: HTML & CSS", level: "BEGINNER" as PlacementLevel, teacherId: ahmad.id, totalMeetings: 12, packagePrice: 2_400_000, pricePerMeeting: 200_000, capacity: 14, schedule: "Sabtu 09:00-12:00", color: "#12B886", description: "Membangun website pertamamu dari nol." },
{ code: "KOD-JS-01", name: "JavaScript Intermediate", level: "INTERMEDIATE" as PlacementLevel, teacherId: budi.id, totalMeetings: 10, packagePrice: 2_500_000, pricePerMeeting: 250_000, capacity: 12, schedule: "Selasa & Kamis 18:45-20:15", color: "#FFB020", description: "DOM, event, async, dan mini project interaktif." },
{ code: "KOD-ARD-01", name: "Arduino & Robotics", level: "INTERMEDIATE" as PlacementLevel, teacherId: rina.id, totalMeetings: 8, packagePrice: 1_800_000, pricePerMeeting: 225_000, capacity: 8, schedule: "Jumat 15:30-17:30", color: "#F65FA7", description: "Rakit dan program robot pertamamu dengan Arduino." },
];
const klass = Object.fromEntries(
await Promise.all(
classesData.map(async (c) => [c.code, await prisma.class.create({ data: { ...c, startDate: addWeeks(-10), status: "ACTIVE" } })]),
),
) as Record<string, Awaited<ReturnType<typeof prisma.class.create>>>;
// ─────────────────────────────────────────────────────────────
// 3. SISWA (10 orang: 4 calon, 4 student, 2 ex student)
// Field: nama, telepon, email, foto, orang tua, sumber lead, status
// ─────────────────────────────────────────────────────────────
const studentsSeed = [
{ key: "andi", fullName: "Andi Pratama", phone: "0812-1111-0001", email: "andi@example.com", parentName: "Budi Pratama", parentPhone: "0812-1111-9001", leadSource: "REFERRAL" as const, status: "STUDENT" as const, joinedAt: addWeeks(-10) },
{ key: "citra", fullName: "Citra Lestari", phone: "0812-1111-0002", email: "citra@example.com", parentName: "Sari Lestari", parentPhone: "0812-1111-9002", leadSource: "WHATSAPP" as const, status: "CALON_STUDENT" as const, joinedAt: null },
{ key: "dimas", fullName: "Dimas Anggara", phone: "0812-1111-0003", email: "dimas@example.com", parentName: "Hendra Anggara", parentPhone: "0812-1111-9003", leadSource: "BANNER" as const, status: "STUDENT" as const, joinedAt: addWeeks(-9) },
{ key: "elsa", fullName: "Elsa Maharani", phone: "0812-1111-0004", email: "elsa@example.com", parentName: "Rina Maharani", parentPhone: "0812-1111-9004", leadSource: "SOCIAL_MEDIA" as const, status: "CALON_STUDENT" as const, joinedAt: null },
{ key: "fajar", fullName: "Fajar Nugroho", phone: "0812-1111-0005", email: "fajar@example.com", parentName: "Agus Nugroho", parentPhone: "0812-1111-9005", leadSource: "WHATSAPP" as const, status: "STUDENT" as const, joinedAt: addWeeks(-8) },
{ key: "gita", fullName: "Gita Permata", phone: "0812-1111-0006", email: "gita@example.com", parentName: "Dwi Permata", parentPhone: "0812-1111-9006", leadSource: "REFERRAL" as const, status: "EX_STUDENT" as const, joinedAt: addWeeks(-40) },
{ key: "hadi", fullName: "Hadi Susanto", phone: "0812-1111-0007", email: "hadi@example.com", parentName: "Tono Susanto", parentPhone: "0812-1111-9007", leadSource: "SOCIAL_MEDIA" as const, status: "STUDENT" as const, joinedAt: addWeeks(-6) },
{ key: "intan", fullName: "Intan Puspita", phone: "0812-1111-0008", email: "intan@example.com", parentName: "Maya Puspita", parentPhone: "0812-1111-9008", leadSource: "BANNER" as const, status: "CALON_STUDENT" as const, joinedAt: null },
{ key: "joko", fullName: "Joko Wijaya", phone: "0812-1111-0009", email: "joko@example.com", parentName: "Slamet Wijaya", parentPhone: "0812-1111-9009", leadSource: "WHATSAPP" as const, status: "STUDENT" as const, joinedAt: addWeeks(-4) },
{ key: "kirana", fullName: "Kirana Dewi", phone: "0812-1111-0010", email: "kirana@example.com", parentName: "Ratna Dewi", parentPhone: "0812-1111-9010", leadSource: "REFERRAL" as const, status: "EX_STUDENT" as const, joinedAt: addWeeks(-36) },
];
const student = {} as Record<string, Awaited<ReturnType<typeof prisma.student.create>>>;
for (const s of studentsSeed) {
student[s.key] = await prisma.student.create({
data: {
fullName: s.fullName, phone: s.phone, email: s.email,
photoUrl: avatar(s.key), parentName: s.parentName, parentPhone: s.parentPhone,
leadSource: s.leadSource, status: s.status, joinedAt: s.joinedAt,
birthDate: new Date("2012-05-10T00:00:00.000Z"),
gender: "MALE", address: "Jl. Merdeka No. 10, Bandung",
},
});
}
// ─────────────────────────────────────────────────────────────
// 4. ENROLLMENT ( siswa ↔ kelas )
// ─────────────────────────────────────────────────────────────
const enrollments = [
{ key: "andi", code: "KOD-PYT-01", status: "ACTIVE" as const },
{ key: "dimas", code: "KOD-SCR-01", status: "ACTIVE" as const },
{ key: "fajar", code: "KOD-WEB-01", status: "ACTIVE" as const },
{ key: "gita", code: "KOD-JS-01", status: "COMPLETED" as const },
{ key: "hadi", code: "KOD-ARD-01", status: "ACTIVE" as const },
{ key: "joko", code: "KOD-PYT-01", status: "ACTIVE" as const },
{ key: "kirana", code: "KOD-SCR-01", status: "COMPLETED" as const },
];
for (const e of enrollments) {
await prisma.enrollment.create({
data: { studentId: student[e.key].id, classId: klass[e.code].id, status: e.status, joinedAt: student[e.key].joinedAt ?? BASE, leftAt: e.status === "COMPLETED" ? addWeeks(-2) : null },
});
}
// ─────────────────────────────────────────────────────────────
// 5. SESSION (pertemuan per kelas) — dasar prorata
// ─────────────────────────────────────────────────────────────
const session: Record<string, { id: string; meetingNumber: number }[]> = {};
for (const c of Object.values(klass)) {
session[c.code] = [];
for (let i = 1; i <= c.totalMeetings; i++) {
const s = await prisma.session.create({
data: { classId: c.id, meetingNumber: i, date: addWeeks(-10 + i - 1), topic: `Pertemuan ${i}: ${c.name}`, teacherId: c.teacherId },
});
session[c.code].push({ id: s.id, meetingNumber: i });
}
}
// ─────────────────────────────────────────────────────────────
// 6. KEHADIRAN (PRESENT/LATE/EXCUSED/SICK/ABSENT)
// Terpakai = jumlah PRESENT + LATE → dasar hitung sisa kuota
// ─────────────────────────────────────────────────────────────
const plan: Record<string, { code: string; statuses: AttendanceStatus[] }> = {
andi: { code: "KOD-PYT-01", statuses: ["PRESENT", "PRESENT", "LATE", "PRESENT", "PRESENT", "PRESENT"] }, // 6 terpakai
dimas: { code: "KOD-SCR-01", statuses: ["PRESENT", "PRESENT", "ABSENT", "PRESENT"] }, // 3 hadir, 1 alpa
fajar: { code: "KOD-WEB-01", statuses: ["PRESENT", "LATE", "PRESENT", "PRESENT", "EXCUSED", "PRESENT"] }, // 5 hadir
gita: { code: "KOD-JS-01", statuses: ["PRESENT", "PRESENT", "PRESENT", "PRESENT", "PRESENT", "PRESENT", "PRESENT", "PRESENT", "PRESENT", "PRESENT"] },
hadi: { code: "KOD-ARD-01", statuses: ["PRESENT", "PRESENT", "PRESENT", "PRESENT"] },
joko: { code: "KOD-PYT-01", statuses: ["PRESENT", "SICK", "PRESENT", "PRESENT", "PRESENT"] },
kirana: { code: "KOD-SCR-01", statuses: ["PRESENT", "PRESENT", "LATE", "PRESENT", "PRESENT", "PRESENT"] },
};
let attendanceCount = 0;
for (const [key, p] of Object.entries(plan)) {
const sessions = session[p.code];
for (let i = 0; i < p.statuses.length; i++) {
await prisma.attendance.create({
data: { sessionId: sessions[i].id, studentId: student[key].id, status: p.statuses[i], recordedById: klass[p.code].teacherId, note: p.statuses[i] === "SICK" ? "Demam" : undefined },
});
attendanceCount++;
}
}
// ─────────────────────────────────────────────────────────────
// 7. PEMBAYARAN PRORATA
// amount = meetingsPaid × pricePerMeeting
// Contoh: Andi 10 × 200.000 = 2.000.000
// Hadir 6 → terpakai 1.200.000 → sisa 4 pertemuan = 800.000
// ─────────────────────────────────────────────────────────────
const paymentsSeed = [
{ key: "andi", code: "KOD-PYT-01", meetingsPaid: 10, method: "TRANSFER" as const, status: "PAID" as const, paidAt: addWeeks(-10) },
{ key: "dimas", code: "KOD-SCR-01", meetingsPaid: 8, method: "CASH" as const, status: "PAID" as const, paidAt: addWeeks(-9) },
{ key: "fajar", code: "KOD-WEB-01", meetingsPaid: 6, method: "QRIS" as const, status: "PAID" as const, paidAt: addWeeks(-8), note: "Bayar 6 pertemuan dulu" },
{ key: "gita", code: "KOD-JS-01", meetingsPaid: 10, method: "TRANSFER" as const, status: "PAID" as const, paidAt: addWeeks(-40) },
{ key: "hadi", code: "KOD-ARD-01", meetingsPaid: 8, method: "TRANSFER" as const, status: "PAID" as const, paidAt: addWeeks(-6) },
{ key: "joko", code: "KOD-PYT-01", meetingsPaid: 5, method: "QRIS" as const, status: "PARTIAL" as const, paidAt: addWeeks(-4), note: "Cicilan 1 dari 2" },
{ key: "kirana", code: "KOD-SCR-01", meetingsPaid: 8, method: "CASH" as const, status: "PAID" as const, paidAt: addWeeks(-36) },
];
let paySeq = 1;
for (const p of paymentsSeed) {
const c = klass[p.code];
const ppm = c.pricePerMeeting ?? Math.round(c.packagePrice / c.totalMeetings);
await prisma.payment.create({
data: {
invoiceNumber: `INV-2026-${String(paySeq++).padStart(4, "0")}`,
studentId: student[p.key].id, classId: c.id,
meetingsPaid: p.meetingsPaid, pricePerMeeting: ppm, amount: p.meetingsPaid * ppm,
method: p.method, status: p.status as PaymentStatus, paidAt: p.paidAt, note: p.note, createdById: sari.id,
},
});
}
// ─────────────────────────────────────────────────────────────
// 8. JURNAL AKTIVITAS + FOTO
// ─────────────────────────────────────────────────────────────
const journalsSeed = [
{ code: "KOD-SCR-01", title: "Membuat Game Ular dengan Scratch", description: "Anak-anak belajar event, loop, dan variabel skor sambil membuat game ular versi mereka sendiri.", tags: ["game", "scratch", "logika"], date: addWeeks(-2), students: ["dimas", "kirana"], photos: ["ular-1", "ular-2", "ular-3"] },
{ code: "KOD-PYT-01", title: "Dasar Variabel & Tipe Data Python", description: "Sesi seru bereksperimen dengan string, integer, dan input dari pengguna.", tags: ["python", "variable", "basic"], date: addWeeks(-3), students: ["andi", "joko"], photos: ["python-1", "python-2"] },
{ code: "KOD-WEB-01", title: "Landing Page Pertama", description: "Setiap siswa mempublikasikan halaman profil pribadinya menggunakan HTML & CSS.", tags: ["html", "css", "project"], date: addWeeks(-1), students: ["fajar"], photos: ["web-1", "web-2", "web-3", "web-4"] },
{ code: "KOD-ARD-01", title: "Sensor Cahaya dengan Arduino", description: "Merakit lampu otomatis yang menyala saat ruangan gelap.", tags: ["arduino", "sensor", "robotik"], date: addDays(-5), students: ["hadi"], photos: ["arduino-1", "arduino-2"] },
];
for (const j of journalsSeed) {
const c = klass[j.code];
await prisma.journal.create({
data: {
classId: c.id, sessionId: session[j.code][0].id, title: j.title, description: j.description,
activityDate: j.date, tags: j.tags, authorId: c.teacherId!,
photos: { create: j.photos.map((s, i) => ({ url: photo(s), caption: `Dokumentasi ${i + 1}`, sortOrder: i })) },
students: { create: j.students.map((k) => ({ studentId: student[k].id })) },
},
});
}
// ─────────────────────────────────────────────────────────────
// 9. RAPORT
// ─────────────────────────────────────────────────────────────
const reportsSeed = [
{ key: "andi", code: "KOD-PYT-01", period: "2026-Term1", scores: [["Logika", 88], ["Computational Thinking", 85], ["Problem Solving", 82], ["Kreativitas", 90], ["Kolaborasi", 86]], notes: "Andi sangat aktif bertanya dan cepat memahami konsep loop." },
{ key: "dimas", code: "KOD-SCR-01", period: "2026-Term1", scores: [["Logika", 80], ["Computational Thinking", 78], ["Problem Solving", 75], ["Kreativitas", 92], ["Kolaborasi", 88]], notes: "Kreativitas Dimas luar biasa, perlu latihan ketelitian." },
{ key: "fajar", code: "KOD-WEB-01", period: "2026-Term1", scores: [["Logika", 84], ["Computational Thinking", 82], ["Problem Solving", 86], ["Kreativitas", 85], ["Kolaborasi", 80]], notes: "Progres pesat di CSS layout." },
] as const;
for (const r of reportsSeed) {
const avg = Math.round(r.scores.reduce((a, [, v]) => a + v, 0) / r.scores.length);
const grade = avg >= 90 ? "A" : avg >= 80 ? "B" : avg >= 70 ? "C" : "D";
await prisma.reportCard.create({
data: {
studentId: student[r.key].id, classId: klass[r.code].id, period: r.period,
teacherId: klass[r.code].teacherId!, finalScore: avg, grade, teacherNotes: r.notes,
attendanceSummary: "Hadir 6 dari 6 pertemuan", publishedAt: addDays(-3),
scores: { create: r.scores.map(([aspect, score]) => ({ aspect, score })) },
},
});
}
// ─────────────────────────────────────────────────────────────
// 10. PLACEMENT TEST (hasil tes penempatan → tampil di detail siswa)
// ─────────────────────────────────────────────────────────────
const placementsSeed = [
{ key: "elsa", level: "INTERMEDIATE" as PlacementLevel, rec: "KOD-JS-01", scores: [["Logika", 82], ["Dasar Coding", 76], ["Problem Solving", 80], ["Kreativitas", 74]] },
{ key: "intan", level: "BEGINNER" as PlacementLevel, rec: "KOD-SCR-01", scores: [["Logika", 62], ["Dasar Coding", 48], ["Problem Solving", 55], ["Kreativitas", 70]] },
{ key: "citra", level: "BEGINNER" as PlacementLevel, rec: "KOD-PYT-01", scores: [["Logika", 50], ["Dasar Coding", 40], ["Problem Solving", 45], ["Kreativitas", 60]] },
{ key: "andi", level: "INTERMEDIATE" as PlacementLevel, rec: "KOD-JS-01", scores: [["Logika", 80], ["Dasar Coding", 78], ["Problem Solving", 72], ["Kreativitas", 68]] },
];
for (const p of placementsSeed) {
const total = Math.round(p.scores.reduce((a, [, v]) => a + v, 0) / p.scores.length);
await prisma.placementTest.create({
data: {
studentId: student[p.key].id, testDate: addDays(-12), levelResult: p.level,
recommendedClassId: klass[p.rec].id, totalScore: total, examinerId: rina.id,
notes: `Direkomendasikan masuk kelas ${klass[p.rec].name}.`,
scores: { create: p.scores.map(([category, score]) => ({ category, score })) },
},
});
}
// ─────────────────────────────────────────────────────────────
// 11. FOLLOW UP (berapa yang harus di-follow up)
// due = nextFollowUpAt <= hari ini && status ∉ (ENROLLED, LOST)
// ─────────────────────────────────────────────────────────────
const followUpsSeed = [
{ key: "citra", status: "CONTACTED" as const, picId: sari.id, next: addDays(-1), last: addDays(-3), channel: "WHATSAPP" as const, activities: [["wa", "Kirim brosur Python Dasar, ortu minta dihubungi lagi."]] },
{ key: "elsa", status: "NEW" as const, picId: budi.id, next: addDays(0), last: null, channel: "SOCIAL_MEDIA" as const, activities: [["wa", "Lead dari Instagram, tanya jadwal kelas."]] },
{ key: "intan", status: "TRIAL" as const, picId: rina.id, next: addDays(2), last: addDays(-1), channel: "BANNER" as const, activities: [["call", "Sudah trial Scratch, tinggal konfirmasi pembayaran."]] },
];
for (const f of followUpsSeed) {
await prisma.followUp.create({
data: {
studentId: student[f.key].id, status: f.status, picId: f.picId,
nextFollowUpAt: f.next, lastContactedAt: f.last, channel: f.channel,
activities: { create: f.activities.map(([type, note]) => ({ type, note, authorId: f.picId })) },
},
});
}
// ─────────────────────────────────────────────────────────────
// 12. SETTINGS
// ─────────────────────────────────────────────────────────────
await prisma.setting.createMany({
data: [
{ key: "academy", value: { name: "Kodeva Academy", address: "Jl. Coding Raya No. 1, Bandung", phone: "0821-1000-2000", email: "halo@kodeva.id" } },
{ key: "leadSources", value: [
{ value: "WHATSAPP", label: "WhatsApp", color: "#22C55E", active: true },
{ value: "REFERRAL", label: "Referral", color: "#7C5CFC", active: true },
{ value: "BANNER", label: "Banner", color: "#FFB020", active: true },
{ value: "SOCIAL_MEDIA", label: "Social Media", color: "#2AA9FF", active: true },
] },
{ key: "currency", value: { code: "IDR", locale: "id-ID", timezone: "Asia/Jakarta" } },
],
});
// ─────────────────────────────────────────────────────────────
// Ringkasan (untuk verifikasi dashboard)
// ─────────────────────────────────────────────────────────────
const [activeStudents, exStudents, followUpDue] = await Promise.all([
prisma.student.count({ where: { status: "STUDENT" } }),
prisma.student.count({ where: { status: "EX_STUDENT" } }),
prisma.followUp.count({ where: { status: { notIn: ["ENROLLED", "LOST"] }, nextFollowUpAt: { lte: addDays(1) } } }),
]);
console.log("✅ Seed selesai.");
console.log(` 👥 Siswa aktif : ${activeStudents}`);
console.log(` 🎓 Ex student : ${exStudents}`);
console.log(` 🔔 Perlu follow up: ${followUpDue}`);
console.log(` 📚 Kelas : ${Object.keys(klass).length}`);
console.log(` 🗓️ Kehadiran : ${attendanceCount} record`);
console.log("\n Login: admin@kodeva.id / password123");
}
main()
.catch((e) => { console.error("❌ Seed gagal:", e); process.exit(1); })
.finally(async () => { await prisma.$disconnect(); });