diff --git a/app/template_generator.py b/app/template_generator.py index 4c43ea4..6dbdca9 100644 --- a/app/template_generator.py +++ b/app/template_generator.py @@ -22,11 +22,11 @@ sys.path.insert(0, os.path.join(ROOT_DIR, "templates", "room-wise")) sys.path.insert(0, os.path.join(ROOT_DIR, "templates", "student-wise")) sys.path.insert(0, os.path.join(ROOT_DIR, "templates", "teacher-wise")) -from template_controller import build_schedule # noqa: E402 +from template_controller import load_data, Scheduler # noqa: E402 from conflict_checker import check_all_conflicts # noqa: E402 from conflict_checker.student_conflict_checker import format_student_conflicts # noqa: E402 from conflict_checker.teacher_conflict_checker import format_teacher_conflicts # noqa: E402 -from template_logger import reset_log, log_error, log_info # noqa: E402 +from template_logger import reset_log, log_error, log_info, log_warning # noqa: E402 from batch_wise_template import generate_batch_wise_templates # noqa: E402 from department_wise_template import generate_department_wise_templates # noqa: E402 @@ -38,6 +38,23 @@ RESULT_DIR = os.path.join(ROOT_DIR, "result", "templates") VIEW_NAMES = ["batch-wise", "department-wise", "room-wise", "student-wise", "teacher-wise"] +def _check_and_log(sessions, label): + """Runs student + teacher conflict checks over `sessions` and logs the result.""" + report = check_all_conflicts(sessions) + if report["has_conflicts"]: + for line in format_student_conflicts(report["student_conflicts"]): + log_error(f"[{label}] STUDENT CONFLICT: {line}") + for line in format_teacher_conflicts(report["teacher_conflicts"]): + log_error(f"[{label}] TEACHER CONFLICT: {line}") + log_warning( + f"[{label}] Found {len(report['student_conflicts'])} student conflict(s) and " + f"{len(report['teacher_conflicts'])} teacher conflict(s)." + ) + else: + log_info(f"[{label}] No conflicts found — clash-free.") + return report + + def clear_result_dir(): """Removes every previous run's output so stale files never linger.""" for view_name in VIEW_NAMES: @@ -59,23 +76,32 @@ def main(): generate_dummy_data() print() - print("Loading data and building clash-free schedule...") - data, sessions = build_schedule() - print(f"Scheduled {len(sessions)} sessions.\n") + log_info("Loading data...") + data = load_data() + scheduler = Scheduler(data) - log_info("Running conflict checks (student/batch and teacher)...") - report = check_all_conflicts(sessions) - if report["has_conflicts"]: - for line in format_student_conflicts(report["student_conflicts"]): - log_error(f"STUDENT CONFLICT: {line}") - for line in format_teacher_conflicts(report["teacher_conflicts"]): - log_error(f"TEACHER CONFLICT: {line}") - log_error( - f"Found {len(report['student_conflicts'])} student conflict(s) and " - f"{len(report['teacher_conflicts'])} teacher conflict(s)." - ) - else: - log_info("No conflicts found — schedule is clash-free for students and teachers.") + # --- Phase 1: general courses (Tue/Thu preferred), self-repaired until clash-free --- + log_info("Phase 1/3: scheduling general courses...") + phase1_sessions = scheduler.phase_1_general_courses() + _check_and_log(phase1_sessions, "Phase 1 (general courses)") + + # --- Phase 2: labs, scheduled against Phase 1's fixed placements --- + log_info("Phase 2/3: scheduling labs...") + phase2_sessions = scheduler.phase_2_labs() + _check_and_log(phase1_sessions + phase2_sessions, "Phase 2 (general courses + labs)") + + # --- Phase 3: remaining theory courses, batch by batch --- + log_info("Phase 3/3: scheduling remaining courses (batch by batch)...") + phase3_sessions = scheduler.phase_3_remaining_courses() + + sessions = phase1_sessions + phase2_sessions + phase3_sessions + log_info( + f"Scheduling complete: {len(phase1_sessions)} general, {len(phase2_sessions)} lab, " + f"{len(phase3_sessions)} remaining = {len(sessions)} total session(s)." + ) + + log_info("Running final conflict check (student/batch and teacher) over the full schedule...") + _check_and_log(sessions, "Final (full schedule)") generators = [ ("batch-wise", generate_batch_wise_templates), diff --git a/controller/template_controller.py b/controller/template_controller.py index cd52175..e829c31 100644 --- a/controller/template_controller.py +++ b/controller/template_controller.py @@ -2,17 +2,23 @@ Loads dummy CSV data and builds a clash-free schedule of sessions that all five templates/*-wise template modules render from. -Scheduling rules (dummy/demo scheduler, not a full CSP solver): - 1. General courses (shared across every batch of a session) are placed - first, only on Tuesday, so those slots are locked in before anything - else and never clash across the batches sharing them. Each general - offering gets `lectures_per_week` sessions. - 2. Lab courses are placed next: each offering gets `labs_per_week` - 180-minute / double-slot sessions, in lab rooms only, on whichever - day/slot-pair is free for the batch, instructor, and room. - 3. Remaining theory sessions (`lectures_per_week` per non-general - offering) fill the rest of the week (Mon/Tue/Wed/Thu/Fri), one - 90-minute slot at a time, avoiding room / instructor / batch clashes. +Scheduling is done in three sequential, independently-verified phases (see +app/template_generator.py for the orchestration + per-phase conflict +checks). Each phase's placements are locked before the next phase starts: +once a (day, slot, room/instructor/batch) combination is marked busy by an +earlier phase, later phases can never reuse it. + + 1. General courses (shared across every batch of a session), preferring + Tuesday/Thursday first. Each offering gets `lectures_per_week` + sessions. If two general courses still land in the same slot for a + batch, the losing session is moved to another day/slot until this + phase is clash-free (see `phase_1_general_courses`). + 2. Labs: each offering gets `labs_per_week` 180-minute / double-slot + sessions, in lab rooms only, scheduled against Phase 1's fixed + placements plus labs placed so far this phase. + 3. Remaining (non-general) theory sessions, scheduled batch by batch in + sorted batch_code order: for each batch, every one of its remaining + offerings is placed and locked before the next batch is considered. Room selection always tries a course's preferred lecture_room_id / lab_room_id first, falling back to another same-type room only if the @@ -131,6 +137,13 @@ class Scheduler: self.instructor_busy.setdefault(key, set()).add(instructor_code) self.batch_busy.setdefault(key, set()).update(batch_codes) + def _unmark_busy(self, day, slot_index, room_id, instructor_code, batch_codes): + key = (day, slot_index) + self.room_busy.get(key, set()).discard(room_id) + self.instructor_busy.get(key, set()).discard(instructor_code) + for b in batch_codes: + self.batch_busy.get(key, set()).discard(b) + def _room_candidates(self, preferred_room_id, room_pool): """Preferred room first, then the rest of the same-type pool.""" preferred = self.data["rooms_by_id"].get(preferred_room_id) @@ -142,7 +155,7 @@ class Scheduler: start = TIME_SLOTS[slot_indices[0]]["start"] end = TIME_SLOTS[slot_indices[-1]]["end"] session_type = "lab" if len(slot_indices) > 1 else "theory" - self.sessions.append({ + session = { "day": day, "slot_indices": slot_indices, "start": start, @@ -157,34 +170,84 @@ class Scheduler: "room_id": room["room_id"], "room_name": room["room_name"], "batch_codes": offering["batch_codes"], - }) + } + self.sessions.append(session) + return session - def schedule_general_courses(self): + def _place_theory_session(self, offering, room_candidates, day_order): + """Finds and locks a free single-slot session; returns the session dict or None.""" + for day in day_order: + for slot_index in TEACHING_SLOT_INDICES: + for room in room_candidates: + if self._is_free(day, slot_index, room["room_id"], offering["instructor_code"], offering["batch_codes"]): + self._mark_busy(day, slot_index, room["room_id"], offering["instructor_code"], offering["batch_codes"]) + return self._add_session(offering, day, [slot_index], room) + return None + + def phase_1_general_courses(self, preferred_days=("Tuesday", "Thursday"), max_repair_attempts=20): + """ + Places every general-course offering's weekly lectures, preferring + `preferred_days` first. Afterwards, self-repairs: any batch left + with two general-course sessions in the same slot has the losing + session unmarked and re-placed (scanning every day) until this + phase's own sessions are clash-free. Returns this phase's sessions. + """ general = [o for o in self.data["offerings"] if o["course"]["is_general"]] + preferred_order = list(preferred_days) + [d for d in DAYS if d not in preferred_days] + phase_start = len(self.sessions) + for offering in general: course = offering["course"] room_candidates = self._room_candidates(course["lecture_room_id"], self.classrooms) - for _ in range(course["lectures_per_week"]): - placed = False - # Tuesday first, then spill to the rest of the week if a - # session can't fit there. - for day in ["Tuesday"] + [d for d in DAYS if d != "Tuesday"]: - for slot_index in TEACHING_SLOT_INDICES: - for room in room_candidates: - if self._is_free(day, slot_index, room["room_id"], offering["instructor_code"], offering["batch_codes"]): - self._mark_busy(day, slot_index, room["room_id"], offering["instructor_code"], offering["batch_codes"]) - self._add_session(offering, day, [slot_index], room) - placed = True - break - if placed: - break - if placed: - break - if not placed: + session = self._place_theory_session(offering, room_candidates, preferred_order) + if session is None: print(f"WARNING: could not place a lecture for general course {offering['course_id']} section {offering['section_id']}") - def schedule_lab_courses(self): + phase_sessions = self.sessions[phase_start:] + self._repair_general_conflicts(phase_sessions, preferred_order, max_repair_attempts) + return phase_sessions + + def _repair_general_conflicts(self, phase_sessions, day_order, max_attempts): + """Moves general-course sessions that clash for a batch to a free slot on any day.""" + from conflict_checker.student_conflict_checker import check_student_conflicts + + any_day_order = list(DAYS) + for _ in range(max_attempts): + conflicts = check_student_conflicts(phase_sessions) + if not conflicts: + return + + # Re-place the last session involved in the first conflict; the + # other session(s) in that cell stay put. + losing_session = conflicts[0]["sessions"][-1] + offering = next( + o for o in self.data["offerings"] + if o["course_id"] == losing_session["course_id"] and o["section_id"] == losing_session["section_id"] + ) + self._unmark_busy( + losing_session["day"], losing_session["slot_indices"][0], + losing_session["room_id"], losing_session["instructor_code"], losing_session["batch_codes"], + ) + self.sessions.remove(losing_session) + phase_sessions.remove(losing_session) + + room_candidates = self._room_candidates(offering["course"]["lecture_room_id"], self.classrooms) + new_session = self._place_theory_session(offering, room_candidates, any_day_order) + if new_session is None: + print(f"WARNING: could not repair general-course conflict for {offering['course_id']} section {offering['section_id']}") + return + phase_sessions.append(new_session) + + print("WARNING: general-course conflicts remained unresolved after max repair attempts") + + def phase_2_labs(self): + """ + Places every lab offering's weekly labs into lab rooms, treating + Phase 1's placements (already marked busy) as fixed. Returns this + phase's sessions. + """ + phase_start = len(self.sessions) offerings = [o for o in self.data["offerings"] if not o["course"]["is_general"] and o["course"]["labs_per_week"] > 0] for offering in offerings: course = offering["course"] @@ -209,33 +272,37 @@ class Scheduler: if not placed: print(f"WARNING: could not place a lab for course {offering['course_id']} section {offering['section_id']} ({offering['batch_codes']})") - def schedule_theory_courses(self): - offerings = [o for o in self.data["offerings"] if not o["course"]["is_general"]] - for offering in offerings: - course = offering["course"] - room_candidates = self._room_candidates(course["lecture_room_id"], self.classrooms) + return self.sessions[phase_start:] - for _ in range(course["lectures_per_week"]): - placed = False - for day in DAYS: - for slot_index in TEACHING_SLOT_INDICES: - for room in room_candidates: - if self._is_free(day, slot_index, room["room_id"], offering["instructor_code"], offering["batch_codes"]): - self._mark_busy(day, slot_index, room["room_id"], offering["instructor_code"], offering["batch_codes"]) - self._add_session(offering, day, [slot_index], room) - placed = True - break - if placed: - break - if placed: - break - if not placed: - print(f"WARNING: could not place a lecture for course {offering['course_id']} section {offering['section_id']} ({offering['batch_codes']})") + def phase_3_remaining_courses(self): + """ + Places every remaining (non-general) theory offering's weekly + lectures, batch by batch in sorted batch_code order: all of one + batch's offerings are placed and locked before the next batch is + considered. Treats Phases 1+2 (already marked busy) as fixed. + Returns this phase's sessions. + """ + phase_start = len(self.sessions) + offerings = [o for o in self.data["offerings"] if not o["course"]["is_general"]] + + for batch in sorted(self.data["batches"], key=lambda b: b["batch_code"]): + batch_code = batch["batch_code"] + batch_offerings = [o for o in offerings if batch_code in o["batch_codes"]] + + for offering in batch_offerings: + course = offering["course"] + room_candidates = self._room_candidates(course["lecture_room_id"], self.classrooms) + for _ in range(course["lectures_per_week"]): + session = self._place_theory_session(offering, room_candidates, DAYS) + if session is None: + print(f"WARNING: could not place a lecture for course {offering['course_id']} section {offering['section_id']} ({offering['batch_codes']})") + + return self.sessions[phase_start:] def run(self): - self.schedule_general_courses() - self.schedule_lab_courses() - self.schedule_theory_courses() + self.phase_1_general_courses() + self.phase_2_labs() + self.phase_3_remaining_courses() return self.sessions diff --git a/logs/template_generator.log b/logs/template_generator.log index bf62da0..5660a2d 100644 --- a/logs/template_generator.log +++ b/logs/template_generator.log @@ -1,4 +1,11 @@ -Timetable generation log - started 2026-09-09T17:48:16.013663 +Timetable generation log - started 2026-09-09T17:59:37.068314 ================================================================================ -[17:48:16] INFO: Running conflict checks (student/batch and teacher)... -[17:48:16] INFO: No conflicts found — schedule is clash-free for students and teachers. +[17:59:37] INFO: Loading data... +[17:59:37] INFO: Phase 1/3: scheduling general courses... +[17:59:37] INFO: [Phase 1 (general courses)] No conflicts found — clash-free. +[17:59:37] INFO: Phase 2/3: scheduling labs... +[17:59:37] INFO: [Phase 2 (general courses + labs)] No conflicts found — clash-free. +[17:59:37] INFO: Phase 3/3: scheduling remaining courses (batch by batch)... +[17:59:37] INFO: Scheduling complete: 6 general, 10 lab, 20 remaining = 36 total session(s). +[17:59:37] INFO: Running final conflict check (student/batch and teacher) over the full schedule... +[17:59:37] INFO: [Final (full schedule)] No conflicts found — clash-free. diff --git a/result/templates/batch-wise/25021519.xlsx b/result/templates/batch-wise/25021519.xlsx index 42ef45d..826ce45 100644 Binary files a/result/templates/batch-wise/25021519.xlsx and b/result/templates/batch-wise/25021519.xlsx differ diff --git a/result/templates/batch-wise/25021520.xlsx b/result/templates/batch-wise/25021520.xlsx index c3af9ff..42b63f9 100644 Binary files a/result/templates/batch-wise/25021520.xlsx and b/result/templates/batch-wise/25021520.xlsx differ diff --git a/result/templates/batch-wise/25031519.xlsx b/result/templates/batch-wise/25031519.xlsx index 2a2788c..79dcbb1 100644 Binary files a/result/templates/batch-wise/25031519.xlsx and b/result/templates/batch-wise/25031519.xlsx differ diff --git a/result/templates/batch-wise/26021519.xlsx b/result/templates/batch-wise/26021519.xlsx index 7d69467..703dc93 100644 Binary files a/result/templates/batch-wise/26021519.xlsx and b/result/templates/batch-wise/26021519.xlsx differ diff --git a/result/templates/batch-wise/26021520.xlsx b/result/templates/batch-wise/26021520.xlsx index 405eecb..91a29a6 100644 Binary files a/result/templates/batch-wise/26021520.xlsx and b/result/templates/batch-wise/26021520.xlsx differ diff --git a/result/templates/batch-wise/26031519.xlsx b/result/templates/batch-wise/26031519.xlsx index 7280a84..82af612 100644 Binary files a/result/templates/batch-wise/26031519.xlsx and b/result/templates/batch-wise/26031519.xlsx differ diff --git a/result/templates/department-wise/CS.xlsx b/result/templates/department-wise/CS.xlsx index 48bc5be..3ef55dc 100644 Binary files a/result/templates/department-wise/CS.xlsx and b/result/templates/department-wise/CS.xlsx differ diff --git a/result/templates/department-wise/EE.xlsx b/result/templates/department-wise/EE.xlsx index ba5f4d0..3e61b9d 100644 Binary files a/result/templates/department-wise/EE.xlsx and b/result/templates/department-wise/EE.xlsx differ diff --git a/result/templates/room-wise/A-101.xlsx b/result/templates/room-wise/A-101.xlsx index 4848058..8e2bb14 100644 Binary files a/result/templates/room-wise/A-101.xlsx and b/result/templates/room-wise/A-101.xlsx differ diff --git a/result/templates/room-wise/A-102.xlsx b/result/templates/room-wise/A-102.xlsx index e5b5fc9..d7d3233 100644 Binary files a/result/templates/room-wise/A-102.xlsx and b/result/templates/room-wise/A-102.xlsx differ diff --git a/result/templates/room-wise/A-103.xlsx b/result/templates/room-wise/A-103.xlsx index fa4c8b9..cb43b09 100644 Binary files a/result/templates/room-wise/A-103.xlsx and b/result/templates/room-wise/A-103.xlsx differ diff --git a/result/templates/room-wise/A-201.xlsx b/result/templates/room-wise/A-201.xlsx index a095eed..b3339ac 100644 Binary files a/result/templates/room-wise/A-201.xlsx and b/result/templates/room-wise/A-201.xlsx differ diff --git a/result/templates/room-wise/A-L01.xlsx b/result/templates/room-wise/A-L01.xlsx index 6d42bcc..d56afdd 100644 Binary files a/result/templates/room-wise/A-L01.xlsx and b/result/templates/room-wise/A-L01.xlsx differ diff --git a/result/templates/room-wise/A-L02.xlsx b/result/templates/room-wise/A-L02.xlsx index d5e69be..642efbe 100644 Binary files a/result/templates/room-wise/A-L02.xlsx and b/result/templates/room-wise/A-L02.xlsx differ diff --git a/result/templates/student-wise/25021519-001.xlsx b/result/templates/student-wise/25021519-001.xlsx index 90d7de1..7fce808 100644 Binary files a/result/templates/student-wise/25021519-001.xlsx and b/result/templates/student-wise/25021519-001.xlsx differ diff --git a/result/templates/student-wise/25021519-002.xlsx b/result/templates/student-wise/25021519-002.xlsx index c33b5fb..3a2e7f7 100644 Binary files a/result/templates/student-wise/25021519-002.xlsx and b/result/templates/student-wise/25021519-002.xlsx differ diff --git a/result/templates/student-wise/25021519-003.xlsx b/result/templates/student-wise/25021519-003.xlsx index 3d40004..f65b015 100644 Binary files a/result/templates/student-wise/25021519-003.xlsx and b/result/templates/student-wise/25021519-003.xlsx differ diff --git a/result/templates/student-wise/25021519-004.xlsx b/result/templates/student-wise/25021519-004.xlsx index 6127ced..572f86f 100644 Binary files a/result/templates/student-wise/25021519-004.xlsx and b/result/templates/student-wise/25021519-004.xlsx differ diff --git a/result/templates/student-wise/25021519-005.xlsx b/result/templates/student-wise/25021519-005.xlsx index 26b9ee0..de764db 100644 Binary files a/result/templates/student-wise/25021519-005.xlsx and b/result/templates/student-wise/25021519-005.xlsx differ diff --git a/result/templates/student-wise/25021520-001.xlsx b/result/templates/student-wise/25021520-001.xlsx index ebbf9ee..d5c55e5 100644 Binary files a/result/templates/student-wise/25021520-001.xlsx and b/result/templates/student-wise/25021520-001.xlsx differ diff --git a/result/templates/student-wise/25021520-002.xlsx b/result/templates/student-wise/25021520-002.xlsx index 7f29d96..248e2a3 100644 Binary files a/result/templates/student-wise/25021520-002.xlsx and b/result/templates/student-wise/25021520-002.xlsx differ diff --git a/result/templates/student-wise/25021520-003.xlsx b/result/templates/student-wise/25021520-003.xlsx index 4d5cc64..0e61d5d 100644 Binary files a/result/templates/student-wise/25021520-003.xlsx and b/result/templates/student-wise/25021520-003.xlsx differ diff --git a/result/templates/student-wise/25021520-004.xlsx b/result/templates/student-wise/25021520-004.xlsx index e0e7b08..0fec187 100644 Binary files a/result/templates/student-wise/25021520-004.xlsx and b/result/templates/student-wise/25021520-004.xlsx differ diff --git a/result/templates/student-wise/25021520-005.xlsx b/result/templates/student-wise/25021520-005.xlsx index b5ff5a0..032de78 100644 Binary files a/result/templates/student-wise/25021520-005.xlsx and b/result/templates/student-wise/25021520-005.xlsx differ diff --git a/result/templates/student-wise/25031519-001.xlsx b/result/templates/student-wise/25031519-001.xlsx index 70a5265..34f515d 100644 Binary files a/result/templates/student-wise/25031519-001.xlsx and b/result/templates/student-wise/25031519-001.xlsx differ diff --git a/result/templates/student-wise/25031519-002.xlsx b/result/templates/student-wise/25031519-002.xlsx index d82ac87..3e0da6d 100644 Binary files a/result/templates/student-wise/25031519-002.xlsx and b/result/templates/student-wise/25031519-002.xlsx differ diff --git a/result/templates/student-wise/25031519-003.xlsx b/result/templates/student-wise/25031519-003.xlsx index deba11f..5ee5436 100644 Binary files a/result/templates/student-wise/25031519-003.xlsx and b/result/templates/student-wise/25031519-003.xlsx differ diff --git a/result/templates/student-wise/25031519-004.xlsx b/result/templates/student-wise/25031519-004.xlsx index 45c0077..fc5a507 100644 Binary files a/result/templates/student-wise/25031519-004.xlsx and b/result/templates/student-wise/25031519-004.xlsx differ diff --git a/result/templates/student-wise/25031519-005.xlsx b/result/templates/student-wise/25031519-005.xlsx index d505112..12cd501 100644 Binary files a/result/templates/student-wise/25031519-005.xlsx and b/result/templates/student-wise/25031519-005.xlsx differ diff --git a/result/templates/student-wise/26021519-001.xlsx b/result/templates/student-wise/26021519-001.xlsx index 6c94f2b..c831220 100644 Binary files a/result/templates/student-wise/26021519-001.xlsx and b/result/templates/student-wise/26021519-001.xlsx differ diff --git a/result/templates/student-wise/26021519-002.xlsx b/result/templates/student-wise/26021519-002.xlsx index 1245cc9..e3ae8f6 100644 Binary files a/result/templates/student-wise/26021519-002.xlsx and b/result/templates/student-wise/26021519-002.xlsx differ diff --git a/result/templates/student-wise/26021519-003.xlsx b/result/templates/student-wise/26021519-003.xlsx index 35cc3a4..3f6d88e 100644 Binary files a/result/templates/student-wise/26021519-003.xlsx and b/result/templates/student-wise/26021519-003.xlsx differ diff --git a/result/templates/student-wise/26021519-004.xlsx b/result/templates/student-wise/26021519-004.xlsx index f6a70e4..add87ac 100644 Binary files a/result/templates/student-wise/26021519-004.xlsx and b/result/templates/student-wise/26021519-004.xlsx differ diff --git a/result/templates/student-wise/26021519-005.xlsx b/result/templates/student-wise/26021519-005.xlsx index 134b34f..eeae274 100644 Binary files a/result/templates/student-wise/26021519-005.xlsx and b/result/templates/student-wise/26021519-005.xlsx differ diff --git a/result/templates/student-wise/26021520-001.xlsx b/result/templates/student-wise/26021520-001.xlsx index 9414d2b..2e02cd2 100644 Binary files a/result/templates/student-wise/26021520-001.xlsx and b/result/templates/student-wise/26021520-001.xlsx differ diff --git a/result/templates/student-wise/26021520-002.xlsx b/result/templates/student-wise/26021520-002.xlsx index 6f03ad4..833ae1d 100644 Binary files a/result/templates/student-wise/26021520-002.xlsx and b/result/templates/student-wise/26021520-002.xlsx differ diff --git a/result/templates/student-wise/26021520-003.xlsx b/result/templates/student-wise/26021520-003.xlsx index 3e8bca1..c2b2036 100644 Binary files a/result/templates/student-wise/26021520-003.xlsx and b/result/templates/student-wise/26021520-003.xlsx differ diff --git a/result/templates/student-wise/26021520-004.xlsx b/result/templates/student-wise/26021520-004.xlsx index 6b03795..b1c327b 100644 Binary files a/result/templates/student-wise/26021520-004.xlsx and b/result/templates/student-wise/26021520-004.xlsx differ diff --git a/result/templates/student-wise/26021520-005.xlsx b/result/templates/student-wise/26021520-005.xlsx index f3aa85c..3401dd2 100644 Binary files a/result/templates/student-wise/26021520-005.xlsx and b/result/templates/student-wise/26021520-005.xlsx differ diff --git a/result/templates/student-wise/26031519-001.xlsx b/result/templates/student-wise/26031519-001.xlsx index 9184c91..9906e10 100644 Binary files a/result/templates/student-wise/26031519-001.xlsx and b/result/templates/student-wise/26031519-001.xlsx differ diff --git a/result/templates/student-wise/26031519-002.xlsx b/result/templates/student-wise/26031519-002.xlsx index 734c43e..ce459bc 100644 Binary files a/result/templates/student-wise/26031519-002.xlsx and b/result/templates/student-wise/26031519-002.xlsx differ diff --git a/result/templates/student-wise/26031519-003.xlsx b/result/templates/student-wise/26031519-003.xlsx index a5f6e91..f4a11dd 100644 Binary files a/result/templates/student-wise/26031519-003.xlsx and b/result/templates/student-wise/26031519-003.xlsx differ diff --git a/result/templates/student-wise/26031519-004.xlsx b/result/templates/student-wise/26031519-004.xlsx index 1e104e7..54cd483 100644 Binary files a/result/templates/student-wise/26031519-004.xlsx and b/result/templates/student-wise/26031519-004.xlsx differ diff --git a/result/templates/student-wise/26031519-005.xlsx b/result/templates/student-wise/26031519-005.xlsx index 24e5e9d..086a2aa 100644 Binary files a/result/templates/student-wise/26031519-005.xlsx and b/result/templates/student-wise/26031519-005.xlsx differ diff --git a/result/templates/teacher-wise/1001.xlsx b/result/templates/teacher-wise/1001.xlsx index fb9d462..136d884 100644 Binary files a/result/templates/teacher-wise/1001.xlsx and b/result/templates/teacher-wise/1001.xlsx differ diff --git a/result/templates/teacher-wise/1002.xlsx b/result/templates/teacher-wise/1002.xlsx index 2099a22..b675099 100644 Binary files a/result/templates/teacher-wise/1002.xlsx and b/result/templates/teacher-wise/1002.xlsx differ diff --git a/result/templates/teacher-wise/1004.xlsx b/result/templates/teacher-wise/1004.xlsx index 6f3b279..0d1ce53 100644 Binary files a/result/templates/teacher-wise/1004.xlsx and b/result/templates/teacher-wise/1004.xlsx differ diff --git a/result/templates/teacher-wise/1006.xlsx b/result/templates/teacher-wise/1006.xlsx index 2b03a6b..d422e89 100644 Binary files a/result/templates/teacher-wise/1006.xlsx and b/result/templates/teacher-wise/1006.xlsx differ