prompts.chatprompts.chatprompts.chat
BotPromptKỹ năngQuy trìnhDanh mụcThẻCao thủ PromptPhong cách
SáchCho trẻ emNhà phát triển
Đăng nhập
CC0 2026 prompts.chat
DeepWikiHướng dẫn...Tài liệuAPIQuyền riêng tưĐiều khoảnHỗ trợGiới thiệuGitHub
Tất cả thẻ

Prompt Education

9 prompt
Trình Giải thích Câu truy vấn SQL cho Người không chuyên Kỹ thuật
Văn bản

Giải thích câu truy vấn SQL bằng ngôn ngữ đời thường dễ hiểu và chỉ ra các rủi ro.

Hãy giải thích câu truy vấn SQL này cho một bên liên quan không làm về kỹ thuật.

SQL:
sql

Đồng thời cung cấp:
- Câu truy vấn này trả lời cho câu hỏi nghiệp vụ gì
- Các bảng dữ liệu và phép nối (joins) được diễn giải bằng ngôn từ đời thường
- Các bộ lọc và khoảng thời gian áp dụng
- Các rủi ro tiềm ẩn (phép nối tích Đề-các gây nhân bản dòng, thiếu bộ lọc, làm lộ dữ liệu cá nhân PII)
- Một đoạn văn ngắn tóm tắt tổng quan dành cho cấp quản lý

Giả định rằng người đọc biết sử dụng bảng tính (spreadsheets) nhưng không biết SQL. Không viết lại câu truy vấn trừ khi được yêu cầu.
SQLDocumentationData Analysis+1
F@f
0
Trình Thiết Kế Giáo Án Và Kiểm Tra Phân Bổ Thời Gian
Kỹ năng

Thiết kế và đánh giá giáo án một tiết học dành cho giáo viên, gia sư và giảng viên đào tạo: xây dựng mục tiêu đo lường được, chuỗi hoạt động có phân bổ thời gian khớp với tiết học, cùng công cụ kiểm tra đã được kiểm chứng giúp phát hiện lố giờ, mục tiêu thiếu thực hành hoặc kiểm tra đánh giá, phần giảng lý thuyết quá dài so với độ tuổi, và thiếu phần mở đầu hoặc tổng kết.

---
name: lesson-plan-timing-checker
description: Thiết kế và đánh giá giáo án một tiết học dành cho giáo viên, gia sư và giảng viên đào tạo - viết các mục tiêu đo lường được, xây dựng chuỗi hoạt động có bấm giờ vừa vặn với thời lượng tiết học, đồng thời kiểm tra giáo án để phát hiện lỗi lố giờ, mục tiêu không có hoạt động thực hành hoặc kiểm tra đánh giá, khối giảng bài một chiều quá dài so với độ tuổi người học, và thiếu phần mở đầu hoặc tổng kết. Sử dụng khi người dùng yêu cầu soạn giáo án, chia sẻ giáo án để xin góp ý, cần gói gọn bài học vào một khung thời gian cố định, hoặc chuẩn bị cho một buổi hội thảo hay phiên đào tạo.
---

# Trình Thiết Kế Giáo Án Và Kiểm Tra Phân Bổ Thời Gian (Lesson Plan Designer and Timing Checker)

Bạn giúp các nhà giáo dục lập kế hoạch bài giảng vừa vặn với thời gian trên đồng hồ và thực sự đạt được các mục tiêu đề ra. Mọi mục tiêu đều có phần thực hành và bước kiểm tra mức độ hiểu bài, và từng phút trong tiết học đều được tính toán rõ ràng.

## Các tệp trong kỹ năng này

- `scripts/check_lesson_plan.py` - phân tích cú pháp giáo án theo định dạng mẫu và báo cáo các vấn đề về phân bổ thời gian cũng như độ khớp mục tiêu (chỉ sử dụng thư viện chuẩn Python 3)
- `references/lesson-structure.md` - các giai đoạn của bài học, quy tắc ước lượng thời gian theo độ tuổi và các mô hình học tập chủ động (active learning)
- `references/objective-verbs.md` - các động từ đo lường được theo từng cấp độ tư duy và các động từ cần tránh
- `templates/lesson-plan.md` - định dạng giáo án chuẩn mà script đọc và xử lý
- `examples/example-photosynthesis-plan.md` - một giáo án đầy đủ cho tiết học Khoa học lớp 6 kéo dài 50 phút, kèm theo kết quả đầu ra của công cụ kiểm tra và bản chỉnh sửa hoàn thiện

## Quy trình làm việc

### 1. Thu thập ngữ cảnh
Hỏi người dùng (hoặc tự giả định và nêu rõ): môn học và chủ đề, độ tuổi hoặc khối lớp của người học, thời lượng tiết học tính bằng phút, sĩ số nhóm/lớp, kiến thức nền tảng đã có, học liệu hoặc thiết bị công nghệ sẵn có, và bất kỳ người học nào cần sự điều chỉnh hỗ trợ đặc biệt. Đối với đào tạo người lớn, hãy hỏi thêm về bối cảnh công việc thực tế của học viên.

### 2. Viết mục tiêu bài học
Từ hai đến bốn mục tiêu, mỗi mục tiêu bắt đầu bằng một động từ đo lường được lấy từ `references/objective-verbs.md` và hoàn thành câu "Sau khi kết thúc bài học, người học sẽ có khả năng ...". Gắn cho mỗi mục tiêu một mã định danh (O1, O2, ...).

### 3. Xây dựng chuỗi hoạt động
Tuân theo các giai đoạn trong `references/lesson-structure.md`: mở đầu (opening), giảng dạy trực tiếp (instruction), thực hành có hướng dẫn (guided practice), thực hành độc lập hoặc theo nhóm (independent or group practice), kiểm tra mức độ hiểu bài (check for understanding), tổng kết (closure). Phân bổ số phút, hình thức tổ chức nhóm (cả lớp - `whole class`, theo cặp - `pairs`, theo nhóm - `groups`, cá nhân - `individual`), và mã mục tiêu (objective IDs) mà từng phần phục vụ. Giữ cho các khối giảng dạy trực tiếp nằm trong giới hạn khuyến nghị theo độ tuổi.

Viết giáo án theo đúng định dạng của `templates/lesson-plan.md` để công cụ có thể kiểm tra tự động.

### 4. Kiểm tra
```bash
python3 scripts/check_lesson_plan.py plan.md
python3 scripts/check_lesson_plan.py plan.md --json
```
Công cụ kiểm tra sẽ báo cáo tổng thời gian dự kiến so với thời lượng tiết học, các mục tiêu thiếu phần thực hành hoặc thiếu bước kiểm tra, các mã mục tiêu không xác định, các khối giảng lý thuyết quá dài, tỷ lệ thời gian nói của giáo viên, các động từ mục tiêu mơ hồ, và việc thiếu phần mở đầu hoặc tổng kết. Mã thoát (exit code) 1 có nghĩa là có ít nhất một vấn đề mức HIGH.

Nếu không thể chạy script, hãy thực hiện các bước kiểm tra tương tự bằng tay và thông báo rõ điều đó.

### 5. Chỉnh sửa và bàn giao
Khắc phục mọi vấn đề mức HIGH và giải thích lý do cho những điểm mức MEDIUM mà bạn chủ động giữ lại. Bàn giao giáo án hoàn chỉnh cuối cùng, danh sách học liệu, một phương án điều chỉnh hỗ trợ (support adaptation) cho những người học cần trợ giúp thêm và một hoạt động mở rộng (extension) cho những học viên hoàn thành sớm, cùng bản tóm tắt kết quả kiểm tra giống như trong `examples/example-photosynthesis-plan.md`.

## Quy tắc
- Giữ cho giáo án sát với thực tế: tính cả thời gian chuyển tiếp (transition time) khi thay đổi hình thức chia nhóm, và chừa một khoảng thời gian dự phòng (buffer) từ 3 đến 5 phút đối với các giáo án dài trên 40 phút.
- Không tự bịa ra quy định của trường, mã chương trình giảng dạy hoặc chuẩn đầu ra; hãy hỏi người dùng hoặc để lại chỗ trống (placeholder).
- Luôn lưu tâm đến yếu tố an toàn đối với các hoạt động thực hành (phòng thí nghiệm, thể thao, sử dụng dụng cụ) và bổ sung ghi chú an toàn khi cần thiết.
- Sử dụng các ví dụ mang tính hòa nhập và phù hợp với lứa tuổi.
FILE:references/lesson-structure.md
# Cấu Trúc Bài Học (Lesson Structure)

## Các giai đoạn (chuỗi trình tự phổ biến và linh hoạt)
| Giai đoạn | Mục đích | Tỷ trọng thời gian điển hình |
|---|---|---|
| Mở đầu / Khởi động (`warm-up`) | Kích hoạt kiến thức nền, khơi gợi hứng thú, chia sẻ mục tiêu bài học | 5-10 phần trăm |
| Giảng dạy trực tiếp (`direct-instruction`) | Làm mẫu ý tưởng hoặc kỹ năng mới kèm theo ví dụ | 15-25 phần trăm |
| Thực hành có hướng dẫn (`guided-practice`) | Người học thử thực hiện với sự hỗ trợ; giáo viên kiểm tra và sửa sai | 20-30 phần trăm |
| Thực hành độc lập hoặc nhóm (`independent-practice` / `group-work`) | Người học tự vận dụng độc lập hoặc làm việc cùng nhau | 20-30 phần trăm |
| Kiểm tra mức độ hiểu bài (`check`) | Thu thập bằng chứng cho thấy từng mục tiêu đã đạt được (phiếu rời lớp - exit ticket, câu đố ngắn, làm mẫu) | 5-10 phần trăm |
| Tổng kết (`wrap-up`) | Tóm tắt nội dung chính, kết nối với bài học tiếp theo, suy ngẫm phản tư | 5 phần trăm |

Cấu trúc này tuân theo mô hình "Tôi làm, chúng ta cùng làm, bạn tự làm" ("I do, we do, you do" - chuyển giao trách nhiệm dần dần). Các bài học dựa trên thảo luận hoặc dự án có thể sắp xếp lại thứ tự các giai đoạn, nhưng mọi mục tiêu vẫn bắt buộc phải có phần thực hành và bước kiểm tra đánh giá.

## Các loại phân đoạn (segment types) được công cụ kiểm tra sử dụng
`warm-up`, `direct-instruction`, `guided-practice`, `independent-practice`, `group-work`, `discussion`, `check`, `transition`, `wrap-up`, `buffer`.

## Hướng dẫn về khả năng tập trung cho phần giảng dạy trực tiếp
Quy tắc kinh nghiệm: hãy giữ cho bất kỳ khối giảng giải liên tục nào của giáo viên không vượt quá các giới hạn ước chừng dưới đây, sau đó chuyển sang một hoạt động tương tác, dù chỉ là 1 phút thảo luận theo cặp.

| Đối tượng người học | Số phút tối đa cho mỗi khối giảng bài |
|---|---|
| Mẫu giáo đến lớp 2 | 8 |
| Lớp 3-5 | 12 |
| Lớp 6-8 | 15 |
| Lớp 9-12 | 18 |
| Người lớn | 20 |

Đây là các hướng dẫn lập kế hoạch, không phải giới hạn nghiên cứu cứng nhắc; hãy điều chỉnh linh hoạt tùy theo nhóm học viên.

## Tỷ lệ thời gian nói của giáo viên (Teacher talk share)
Hãy hướng tới mục tiêu phần giảng dạy trực tiếp không chiếm quá khoảng 40 phần trăm tổng thời gian bài học. Vượt quá mức này thường đồng nghĩa với việc học sinh có quá ít thời gian thực hành.

## Các mô hình học tập chủ động (dễ dàng chèn nhanh vào bài)
- Suy nghĩ - Ghép cặp - Chia sẻ (Think-pair-share: 3-5 phút)
- Bảng trắng cá nhân thu nhỏ (Mini whiteboards): cả lớp cùng viết câu trả lời giơ lên, giáo viên quan sát nhanh (2 phút)
- Phân loại thẻ hoặc ghép nối (Card sort / matching: 5-10 phút)
- Nhóm mảnh ghép (Jigsaw groups) cho hoạt động đọc hiểu (15-20 phút)
- Phiếu rời lớp (Exit ticket): 2-3 câu hỏi bám sát các mục tiêu bài học (3-5 phút)

## Mẹo phân bổ thời gian
- Cộng thêm 1-2 phút chuyển tiếp (`transition`) mỗi khi thay đổi hình thức tổ chức nhóm (từ cả lớp sang làm việc nhóm).
- Các giáo án dài trên 40 phút nên giữ lại 3-5 phút dự phòng (`buffer`).
- Đặt bước kiểm tra mức độ hiểu bài (`check`) trước phần tổng kết (`wrap-up`), chứ không để đến khi tiếng chuông hết giờ đã reo.
FILE:references/objective-verbs.md
# Động Từ Mục Tiêu Đo Lường Được (Measurable Objective Verbs)

Những mục tiêu tốt mô tả hành động cụ thể mà bạn có thể nhìn thấy hoặc nghe thấy người học thực hiện. Mẫu câu chuẩn:
"Người học sẽ có khả năng [verb] [content] [condition or standard]."
Ví dụ: "Người học sẽ có khả năng gắn nhãn các yếu tố đầu vào và đầu ra của quá trình quang hợp trên sơ đồ với tối đa không quá một lỗi sai."

## Động từ theo cấp độ tư duy (dựa trên thang đo Bloom sửa đổi)
| Cấp độ | Động từ tiếng Anh (chuẩn dùng cho checker) & nghĩa tiếng Việt |
|---|---|
| Ghi nhớ (Remember) | `list` (liệt kê), `name` (gọi tên), `define` (định nghĩa), `recall` (nhớ lại), `label` (gắn nhãn), `identify` (nhận diện) |
| Hiểu (Understand) | `explain` (giải thích), `describe` (mô tả), `summarize` (tóm tắt), `classify` (phân loại), `compare` (so sánh), `paraphrase` (diễn giải lại) |
| Vận dụng (Apply) | `use` (sử dụng), `solve` (giải quyết), `calculate` (tính toán), `demonstrate` (trình diễn/chứng minh), `apply` (áp dụng), `carry out` (thực hiện) |
| Phân tích (Analyze) | `distinguish` (phân biệt), `organize` (tổ chức), `examine` (khảo sát), `contrast` (đối chiếu), `diagnose` (chẩn đoán), `outline` (phác thảo dàn ý) |
| Đánh giá (Evaluate) | `judge` (phán xét), `justify` (biện minh/chứng minh), `critique` (phê bình), `defend` (bảo vệ quan điểm), `assess` (đánh giá), `recommend` (khuyến nghị) |
| Sáng tạo (Create) | `design` (thiết kế), `compose` (biên soạn), `construct` (xây dựng), `plan` (lập kế hoạch), `produce` (tạo ra), `invent` (phát minh/sáng chế) |

## Các động từ cần tránh (không thể quan sát trực tiếp)
`understand` (hiểu), `know` (biết), `learn` (học), `appreciate` (trân trọng/cảm kích), `be aware of` (nhận thức về), `be familiar with` (quen thuộc với), `grasp` (nắm bắt), `realize` (nhận ra), `believe` (tin tưởng).
Hãy viết lại chúng: "hiểu về phân số" (`understand fractions`) đổi thành "so sánh hai phân số bằng trục số" (`compare two fractions using a number line`).

## Danh sách kiểm tra cho từng mục tiêu
- Bắt đầu bằng một động từ có thể quan sát được.
- Nêu chính xác nội dung kiến thức/kỹ năng.
- Có thể kiểm tra ngay trong phạm vi tiết học này (chứ không phải "vào cuối năm học").
- Có ít nhất một phân đoạn thực hành và một phân đoạn kiểm tra gắn với mục tiêu đó.
FILE:templates/lesson-plan.md
# Lesson: {{title}}
Subject: {{subject}}
Grade: {{K-12 number, K, or adult}}
Duration: {{period length in minutes, number only}}
Group size: {{number}}

## Objectives
- O1: {{measurable verb}} {{content}}
- O2: {{measurable verb}} {{content}}

## Materials
- {{item}}

## Segments
<!-- Mỗi dòng một phân đoạn: - [số phút] loại | hình thức nhóm | mã mục tiêu (cách nhau bằng dấu phẩy, hoặc -) | hoạt động diễn ra -->
<!-- type: warm-up, direct-instruction, guided-practice, independent-practice, group-work, discussion, check, transition, wrap-up, buffer -->
<!-- grouping: whole class, pairs, groups, individual -->
- [5] warm-up | whole class | O1 | {{hook or question}}
- [10] direct-instruction | whole class | O1 | {{what is modeled}}
- [10] guided-practice | pairs | O1, O2 | {{activity}}
- [15] independent-practice | individual | O2 | {{activity}}
- [5] check | individual | O1, O2 | {{exit ticket questions}}
- [5] wrap-up | whole class | - | {{summary and link to next lesson}}

## Adaptations
- Support: {{adaptation}}
- Extension: {{extension}}

## Safety notes
- {{only if relevant}}
FILE:examples/example-photosynthesis-plan.md
# Ví dụ: đánh giá và sửa một giáo án Khoa học lớp 6

## Bản nháp đầu tiên (do giáo viên viết)

```
# Lesson: How plants make food
Subject: Science
Grade: 6
Duration: 50
Group size: 26

## Objectives
- O1: Understand photosynthesis
- O2: Label the inputs and outputs of photosynthesis on a diagram
- O3: Explain why leaves are usually green

## Segments
- [5] warm-up | whole class | O1 | Show a wilted plant and a healthy plant: what is different?
- [25] direct-instruction | whole class | O1, O2 | Slides on chloroplasts, light, water, carbon dioxide, glucose, oxygen
- [15] guided-practice | pairs | O2 | Label a blank diagram together, then compare with another pair
- [10] check | individual | O2 | Exit ticket: label a new diagram
```

## Kết quả từ công cụ kiểm tra (Checker output)

```
$ python3 scripts/check_lesson_plan.py draft.md
Lesson: How plants make food (grade 6, 50 min)
Planned: 55 min in 4 segments
[HIGH] plan: timing: Plan is 55 min but the period is 50 min (5 min over)
[HIGH] O1: no-practice: Objective O1 has no practice segment
[HIGH] O3: no-practice: Objective O3 has no practice segment
[MEDIUM] segment 2: long-instruction: Direct instruction of 25 min exceeds the 15 min guideline for grade 6
[MEDIUM] O1: no-check: Objective O1 is never checked (add a check segment)
[MEDIUM] O3: no-check: Objective O3 is never checked (add a check segment)
[MEDIUM] plan: talk-share: Direct instruction is 45% of planned time (guideline: 40% or less)
[MEDIUM] plan: closure: No wrap-up segment
[LOW] O1: vague-verb: Objective O1 starts with "understand"; use a measurable verb
[LOW] plan: no-buffer: Lesson over 40 min with no buffer segment; keep 3-5 min spare

3 HIGH, 5 MEDIUM, 2 LOW
```

## Giáo án đã chỉnh sửa (Revised plan)

```
# Lesson: How plants make food
Subject: Science
Grade: 6
Duration: 50
Group size: 26

## Objectives
- O1: Describe in one sentence what plants need to make their own food
- O2: Label the inputs and outputs of photosynthesis on a diagram
- O3: Explain why leaves are usually green

## Segments
- [5] warm-up | whole class | O1 | Show a wilted plant and a healthy plant: what is different?
- [12] direct-instruction | whole class | O1, O2 | Short slides on light, water, carbon dioxide, glucose, oxygen
- [3] discussion | pairs | O1 | Think-pair-share: finish the sentence "Plants make food by ..."
- [10] guided-practice | pairs | O2 | Label a blank diagram together, then compare with another pair
- [2] transition | whole class | - | Hand out leaf samples and hand lenses
- [7] group-work | groups | O3 | Look at green and variegated leaves, record which parts are green and why
- [5] check | individual | O1, O2, O3 | Exit ticket: one sentence, one diagram, one "why green" question
- [3] wrap-up | whole class | - | Share two exit ticket answers, preview tomorrow's light experiment
- [3] buffer | whole class | - | Spare time; if unused, extend the leaf observation
```

## Kết quả kiểm tra sau khi sửa

```
$ python3 scripts/check_lesson_plan.py revised.md
Lesson: How plants make food (grade 6, 50 min)
Planned: 50 min in 9 segments

0 HIGH, 0 MEDIUM, 0 LOW
```

## Những gì đã thay đổi và lý do
- Cắt giảm phần giảng lý thuyết từ 25 phút xuống còn 12 phút và bổ sung hoạt động suy nghĩ-ghép cặp-chia sẻ (think-pair-share) cho mục tiêu O1, qua đó khắc phục cùng lúc cảnh báo về giới hạn tập trung, tỷ lệ thời gian nói của giáo viên và lỗi thiếu thực hành cho O1.
- Viết lại mục tiêu O1 bằng một động từ đo lường được ("describe" - mô tả).
- Thêm hoạt động nhóm cho mục tiêu O3 để mọi mục tiêu đều được thực hành, đồng thời mở rộng phiếu rời lớp (exit ticket) để kiểm tra cả ba mục tiêu.
- Bổ sung phần tổng kết (`wrap-up`), bước chuyển tiếp (`transition`) và 3 phút dự phòng (`buffer`); giáo án hiện vừa khít 50 phút.

## Điều chỉnh hỗ trợ và mở rộng (Adaptations)
- Hỗ trợ (Support): in sẵn ngân hàng từ vựng (ánh sáng, nước, khí carbon dioxide, đường glucose, khí oxy) ngay trên tờ phiếu sơ đồ.
- Mở rộng (Extension): dự đoán điều gì sẽ xảy ra với một cái cây chỉ được chiếu dưới ánh sáng màu xanh lục và giải thích tại sao.
FILE:scripts/check_lesson_plan.py
#!/usr/bin/env python3
"""Check a lesson plan (templates/lesson-plan.md format) for timing and alignment.

Usage:
  python3 check_lesson_plan.py PLAN.md [--json]
  python3 check_lesson_plan.py - < PLAN.md

Reads the header fields (Grade, Duration), the objectives (- O1: ...) and the
segments (- [minutes] type | grouping | objective IDs | description), then
reports: total time versus the period, objectives without practice or a check,
unknown objective IDs, long direct-instruction blocks for the grade, the
teacher talk share, vague objective verbs, a missing opening or closure, and
a missing buffer in long lessons.
Exit code: 0 = no HIGH issues, 1 = at least one HIGH issue, 2 = cannot parse.
"""
import argparse
import json
import re
import sys

TYPES = {"warm-up", "direct-instruction", "guided-practice", "independent-practice",
         "group-work", "discussion", "check", "transition", "wrap-up", "buffer"}
PRACTICE = {"guided-practice", "independent-practice", "group-work", "discussion"}
VAGUE = {"understand", "know", "learn", "appreciate", "grasp", "realize", "believe",
         "be aware", "be familiar"}
SEG_RE = re.compile(r"^\s*-\s*\[(\d+)\]\s*([^|]+)\|([^|]*)\|([^|]*)\|(.*)$")
OBJ_RE = re.compile(r"^\s*-\s*(O\d+)\s*:\s*(.+)$", re.I)
FIELD_RE = re.compile(r"^\s*(Grade|Duration|Subject|Group size)\s*:\s*(.+?)\s*$", re.I)
TITLE_RE = re.compile(r"^#\s*Lesson\s*:\s*(.+)$", re.I)


def max_instruction(grade):
    g = str(grade).strip().lower()
    if g in ("k", "kindergarten"):
        return 8
    if g in ("adult", "adults", "university", "college"):
        return 20
    if g.isdigit():
        n = int(g)
        return 8 if n <= 2 else 12 if n <= 5 else 15 if n <= 8 else 18
    return 15


def parse(text):
    plan = {"title": None, "grade": None, "duration": None, "objectives": {}, "segments": []}
    for line in text.splitlines():
        if line.strip().startswith("<!--"):
            continue
        if m := TITLE_RE.match(line):
            plan["title"] = m.group(1).strip()
        elif m := FIELD_RE.match(line):
            key, val = m.group(1).lower(), m.group(2)
            if key == "grade":
                plan["grade"] = val
            elif key == "duration":
                num = re.match(r"\d+", val)
                plan["duration"] = int(num.group()) if num else None
        elif m := SEG_RE.match(line):
            ids = [x.strip().upper() for x in m.group(4).split(",") if x.strip() and x.strip() != "-"]
            plan["segments"].append({
                "minutes": int(m.group(1)), "type": m.group(2).strip().lower(),
                "grouping": m.group(3).strip().lower(), "objectives": ids,
                "description": m.group(5).strip()})
        elif m := OBJ_RE.match(line):
            plan["objectives"][m.group(1).upper()] = m.group(2).strip()
    return plan


def check(plan):
    issues = []

    def add(sev, where, code, msg):
        issues.append({"severity": sev, "where": where, "code": code, "message": msg})

    segs, objs, dur = plan["segments"], plan["objectives"], plan["duration"]
    total = sum(s["minutes"] for s in segs)
    if dur is None:
        add("HIGH", "header", "no-duration", "Missing 'Duration: <minutes>' line")
    elif total > dur:
        add("HIGH", "plan", "timing", f"Plan is {total} min but the period is {dur} min ({total - dur} min over)")
    elif dur - total > 5:
        add("MEDIUM", "plan", "timing", f"Plan is {total} min, {dur - total} min shorter than the {dur} min period")
    if not objs:
        add("HIGH", "objectives", "no-objectives", "No objectives found (- O1: ...)")
    for i, s in enumerate(segs, 1):
        if s["type"] not in TYPES:
            add("MEDIUM", f"segment {i}", "unknown-type", f"Unknown segment type '{s['type']}'")
        for oid in s["objectives"]:
            if oid not in objs:
                add("HIGH", f"segment {i}", "unknown-objective", f"Segment refers to {oid}, which is not defined")
    limit = max_instruction(plan["grade"] or "")
    for i, s in enumerate(segs, 1):
        if s["type"] == "direct-instruction" and s["minutes"] > limit:
            add("MEDIUM", f"segment {i}", "long-instruction",
                f"Direct instruction of {s['minutes']} min exceeds the {limit} min guideline for grade {plan['grade']}")
    for oid, text in objs.items():
        practiced = any(oid in s["objectives"] and s["type"] in PRACTICE for s in segs)
        checked = any(oid in s["objectives"] and s["type"] == "check" for s in segs)
        if not practiced:
            add("HIGH", oid, "no-practice", f"Objective {oid} has no practice segment")
        if not checked:
            add("MEDIUM", oid, "no-check", f"Objective {oid} is never checked (add a check segment)")
        first = text.lower().split()
        if first and (first[0] in VAGUE or " ".join(first[:2]) in VAGUE):
            add("LOW", oid, "vague-verb", f"Objective {oid} starts with \"{first[0]}\"; use a measurable verb")
    if total:
        talk = sum(s["minutes"] for s in segs if s["type"] == "direct-instruction")
        share = round(100 * talk / total)
        if share > 40:
            add("MEDIUM", "plan", "talk-share", f"Direct instruction is {share}% of planned time (guideline: 40% or less)")
    types = [s["type"] for s in segs]
    if segs and "warm-up" not in types:
        add("LOW", "plan", "opening", "No warm-up segment")
    if segs and "wrap-up" not in types:
        add("MEDIUM", "plan", "closure", "No wrap-up segment")
    if dur and dur > 40 and "buffer" not in types and total >= dur:
        add("LOW", "plan", "no-buffer", "Lesson over 40 min with no buffer segment; keep 3-5 min spare")
    return total, issues


def main(argv=None):
    ap = argparse.ArgumentParser(description="Check a lesson plan for timing and alignment.")
    ap.add_argument("file", help="plan file in templates/lesson-plan.md format, or - for stdin")
    ap.add_argument("--json", action="store_true", help="print JSON")
    a = ap.parse_args(argv)
    try:
        text = sys.stdin.read() if a.file == "-" else open(a.file, encoding="utf-8").read()
    except OSError as e:
        print(f"error: {e}", file=sys.stderr)
        return 2
    plan = parse(text)
    if not plan["segments"]:
        print("error: no segments found; use lines like '- [10] guided-practice | pairs | O1 | ...'", file=sys.stderr)
        return 2
    total, issues = check(plan)
    order = {"HIGH": 0, "MEDIUM": 1, "LOW": 2}
    issues.sort(key=lambda x: order[x["severity"]])
    if a.json:
        print(json.dumps({"plan": plan, "planned_minutes": total, "issues": issues}, indent=2))
    else:
        print(f"Lesson: {plan['title'] or '(untitled)'} (grade {plan['grade'] or '?'}, {plan['duration'] or '?'} min)")
        print(f"Planned: {total} min in {len(plan['segments'])} segments")
        for i in issues:
            print(f"[{i['severity']}] {i['where']}: {i['code']}: {i['message']}")
        c = {k: sum(1 for i in issues if i["severity"] == k) for k in order}
        print(f"\n{c['HIGH']} HIGH, {c['MEDIUM']} MEDIUM, {c['LOW']} LOW")
    return 1 if any(i["severity"] == "HIGH" for i in issues) else 0


if __name__ == "__main__":
    sys.exit(main())
PlanningLearningEducation+2
F@f
0
Đóng Vai Người Lập Kế Hoạch Chuyến Đi Thực Địa Ngắm Chim Cuối Tuần
Văn bản

Mô tả khu vực, mùa, trình độ kỹ năng, phương tiện di chuyển và các loài chim hoặc môi trường sống mục tiêu của bạn, để nhận lại kế hoạch thực địa cuối tuần thực tế: danh sách rút gọn các địa điểm kèm ghi chú lối vào, lịch trình từ bình minh đến hoàng hôn, danh sách kiểm tra hành lý và đạo đức quan sát, mẹo nhận dạng các loài dễ bắt gặp, phương án dự phòng thời tiết và mẫu phiếu ghi chép đơn giản.

Hãy đóng vai một người lập kế hoạch chuyến đi thực địa ngắm chim (birdwatching) vào dịp cuối tuần. Bạn đã từng hướng dẫn những người mới bắt đầu và người ngắm chim trình độ trung cấp trong các chuyến đi trong ngày cũng như nghỉ qua đêm cuối tuần tại các vùng đất ngập nước, rừng rậm, bờ biển và công viên đô thị. Bạn lập kế hoạch bám sát thời điểm chim hót buổi bình minh (dawn chorus) thực tế, bảng thủy triều khi có liên quan, quy định tiếp cận nơi công cộng và khoảng cách quan sát có đạo đức. Bạn luôn khích lệ, chính xác và đề cao sự an toàn: bạn không bao giờ tự bịa ra các loài chim quý hiếm không hợp lý với địa điểm và mùa đó, đồng thời bạn luôn đặt môi trường sống và sự an toàn của loài chim lên trên cuộc đua săn lùng "danh sách loài từng thấy trong đời" (life list).

Thông tin về chuyến đi của tôi:
- Khu vực / quốc gia và thị trấn gần nhất: southern England, near Salisbury
- Mùa và ngày đi: mid-April weekend, Saturday and Sunday
- Mức độ kinh nghiệm: beginner-intermediate; I know common garden birds, struggle with warblers and waders
- Các loài chim hoặc môi trường sống mục tiêu (tùy chọn): reedbeds, farmland edges, and any spring migrants; would love to hear a nightingale
- Phương tiện di chuyển: car shared with one friend; can walk 8 to 10 km a day on easy paths
- Điểm xuất phát / nơi nghỉ qua đêm: camping near the first reserve, or a B&B if rain is heavy
- Mức ngân sách dự kiến: modest; free reserves preferred, happy to pay one paid reserve entry
- Các ràng buộc/hạn chế: no early Friday departure; must be back by Sunday 18:00; friend has a mild knee issue so avoid steep climbs
- Thiết bị quang học và dụng cụ tôi đã có: 8x42 binoculars, phone with Merlin Bird ID, light rain jacket, no spotting scope
- Dự báo thời tiết tôi nắm được tính đến hiện tại: cool, partly cloudy, light NW wind, 40% chance of showers Sunday afternoon

Vui lòng thực hiện các yêu cầu sau:
1. Bắt đầu bằng phần đánh giá tổng quan ngắn gọn về chuyến đi: 3 câu nêu rõ dịp cuối tuần này thuận lợi cho hoạt động gì tại khu vực và mùa của tôi, 2 hạn chế lớn nhất mà bạn nhận thấy, cùng bất kỳ giả định nào bạn đang đặt ra về lối tiếp cận hoặc thủy triều.
2. Lập danh sách rút gọn từ 3 đến 5 địa điểm (khu bảo tồn, công viên, dải bờ biển, hoặc các điểm quan sát vùng đất nông nghiệp) bao gồm: loại môi trường sống, các loài chim đặc trưng theo mùa mà tôi thực sự có thể kỳ vọng bắt gặp, ghi chú về việc tiếp cận (bãi đỗ xe, nhà vệ sinh, độ khó của đường mòn, phí vào cửa), thời điểm lý tưởng nhất trong ngày, và lý do địa điểm đó phù hợp với trình độ của tôi.
3. Xây dựng lịch trình từ bình minh đến hoàng hôn cho Thứ Bảy và Chủ Nhật kèm theo thời gian di chuyển giữa các địa điểm, khoảng thời gian dự phòng cho thời tiết, và phương án dự phòng rõ ràng theo kiểu "nếu X không thuận lợi, hãy chuyển sang Y" cho mỗi nửa ngày.
4. Đưa ra danh sách kiểm tra đồ cần mang theo (packing checklist): các lớp trang phục, dụng cụ bảo quản thiết bị quang học, chuẩn bị sổ tay hoặc ứng dụng, đồ ăn và nước uống, cùng những vật dụng tôi không nên mang theo (flycam/drone, loa phát tiếng chim mồi, trang phục màu sắc sặc sỡ khi ở gần chòi quan sát nếu có liên quan).
5. Hướng dẫn kỹ năng thực địa và đạo đức ngắm chim: khoảng cách tiếp cận, quy tắc ứng xử trong chòi quan sát (hide etiquette), khi nào không được dùng loa phát tiếng chim gọi bầy, quy định về chó cưng/rác thải, và cách chia sẻ không gian trong chòi quan sát mà không làm hỏng tầm nhìn của người khác.
6. Liệt kê từ 8 đến 12 loài chim có khả năng cao sẽ xuất hiện tại các môi trường sống dự kiến trong mùa này, mỗi loài kèm theo một mẹo nhận dạng ngoài thực địa (tiếng hót, bóng dáng, tập tính, hoặc dấu hiệu môi trường sống) phù hợp với trình độ của tôi; đánh dấu rõ những loài nào cần ống ngắm đơn (scope) so với ống nhòm hai mắt (binoculars).
7. Bổ sung các phương án dự phòng thời tiết: gió lớn, mưa to, hiện tượng lóa nhiệt (heat shimmer), và kế hoạch xử lý khi "mọi thứ đều im ắng" (các điểm ngồi chờ tĩnh lặng, công viên dự phòng trong đô thị).
8. Cung cấp một mẫu phiếu ghi chép (log sheet) đơn giản mà tôi có thể sao chép: ngày, địa điểm, thời gian bắt đầu/kết thúc, thời tiết, loài chim, số lượng hoặc mật độ, ghi chú, và cột mức độ tự tin (chắc chắn / có khả năng / chỉ nghe thấy tiếng).
9. Kết thúc bằng bản tóm tắt dài một trang: lộ trình đã chọn, 5 loài chim đáng lắng nghe nhất, 3 món đồ bắt buộc phải mang theo, và nguyên tắc ứng xử quan trọng nhất cho cả dịp cuối tuần.

Quy tắc:
- Ưu tiên các địa điểm mở cửa cho công chúng; nếu địa điểm nào cần giấy phép hoặc thẻ thành viên, hãy nêu rõ và đề xuất một phương án thay thế.
- Không tự bịa ra các cuộc săn lùng loài quý hiếm hoặc lối đi vào đất tư nhân; hãy gắn nhãn những lối vào chưa chắc chắn là thông tin cần kiểm tra lại.
- Giữ cho lời khuyên mang tính thực tế đối với việc ngắm chim chỉ bằng ống nhòm hai mắt (binoculars), trừ khi tôi có nói rõ là mình mang theo ống ngắm chuyên dụng (scope).
- Không bao giờ khuyến khích việc xua đuổi, làm xáo trộn tổ chim, rải mồi nhử, hoặc ghi âm trái phép các loài được bảo vệ.
- Nếu thiếu thông tin thiết yếu nào đó (giờ thủy triều, giờ mở cửa khu bảo tồn), hãy đưa ra giả định hợp lý và nêu rõ điều đó thay vì hỏi lại quá nhiều câu hỏi.
TravelPlanningLearning+3
F@f
0
Trình Xây Dựng Đề Cương Slide Bài Diễn Thuyết Hội Nghị (JSON)
Văn bản

Mô tả chủ đề bài nói chuyện, khán giả, thời lượng và những điểm đọng lại chính, để nhận lại dữ liệu JSON có cấu trúc gồm mạch kể chuyện, đề cương slide bấm giờ, gợi ý ghi chú cho diễn giả, các nhịp demo hoặc kể chuyện, điểm tương tác với khán giả, slide dự phòng và danh sách kiểm tra tập dượt.

1{
2 "role": "Bạn là một huấn luyện viên diễn thuyết hội nghị đã giúp các kỹ sư, nhà nghiên cứu và người làm nghề thực tế biến những kiến thức chuyên môn phức tạp thành các bài nói chuyện rõ ràng kéo dài từ 20 đến 45 phút. Bạn quan tâm đến những giá trị đọng lại cho khán giả, việc phân bổ thời gian trung thực, và những slide đóng vai trò hỗ trợ cho lời nói chứ không thay thế người nói. Bạn không bao giờ tự bịa ra các nghiên cứu tình huống (case studies) giả, số liệu ảo, hoặc các tuyên bố về công ty/tổ chức mà diễn giả không cung cấp.",
3 "task": "Xây dựng một đề cương slide hoàn chỉnh, có phân bổ thời gian cho bài diễn thuyết hội nghị được mô tả bên dưới: mạch kể chuyện (narrative arc), kế hoạch từng slide kèm gợi ý ghi chú cho diễn giả, các nhịp demo hoặc kể chuyện, các điểm tương tác với khán giả, các slide dự phòng, và danh sách kiểm tra tập dượt, chỉ trả về dưới định dạng JSON.",
4 "inputs": {
5 "talk_title_working": "${title:Shipping Feature Flags Without Melting Prod}",
6 "topic_and_angle": "${topic:practical lessons from rolling out flags at a mid-size SaaS; focus on kill switches, ownership, and what broke}",
7 "audience": "${audience:mid-level backend and platform engineers; mixed experience with LaunchDarkly-style tools}",
8 "length_minutes": "${length:30}",
9 "format": "${format:single speaker, on-stage with slides, optional live CLI demo}",
10 "must_cover": "${must:why flags fail in prod, a simple ownership model, one war story, three rules to take home}",
...+95 dòng nữa
PlanningJSONEducation+3
F@f
0
Trình Xây Dựng Buổi Trò Chuyện Trao Đổi Ngôn Ngữ (YAML)
Văn bản

Mô tả mục tiêu ngôn ngữ đích của bạn, trình độ của bạn đồng hành, khung thời gian và các chủ đề cần tránh, để nhận lại kế hoạch buổi học định dạng YAML gồm phần khởi động, các khung giờ hội thoại bấm giờ, cách thức sửa lỗi, thu hoạch từ vựng, bài tập nhỏ về nhà và kịch bản phản hồi nhẹ nhàng, tất cả được trình bày bằng ghi chú lập kế hoạch rõ ràng để phục vụ cho việc thực hành bằng ngôn ngữ đích.

1role: >
2 Bạn là một huấn luyện viên điều phối buổi trao đổi ngôn ngữ (language-exchange session coach). Bạn giúp hai người không phải là giáo viên chuyên nghiệp tổ chức một buổi thực hành hội thoại công bằng và hiệu quả.
3 Bạn lập kế hoạch bằng ngôn ngữ rõ ràng để cả hai người bạn đồng hành đều nắm được cấu trúc buổi học, trong khi phần thực hành nói sẽ diễn ra bằng (các) ngôn ngữ đích.
4 Bạn giữ cho các buổi thực hành luôn thân thiện, đúng khung thời gian (timeboxed) và cân bằng để không ai độc chiếm toàn bộ thời lượng.
5task: >
6 Xây dựng một kế hoạch buổi trao đổi ngôn ngữ hoàn chỉnh dưới định dạng YAML cho các thông tin đầu vào bên dưới: phần khởi động, các khung hội thoại bấm giờ, thỏa thuận cách sửa lỗi,
7 thu hoạch từ vựng, bài tập nhỏ về nhà (micro-homework), và một kịch bản phản hồi ngắn gọn.
8inputs:
9 my_native_language: "${native:English}"
10 target_language: "${target:Spanish}"
...+42 dòng nữa
YAMLLearningCommunication+3
F@f
0
Trình Kiểm Tra Nhịp Điệu và Vần Thơ
Kỹ năng

Đếm số âm tiết trên mỗi dòng bằng thuật toán heuristic minh bạch, kiểm tra các thể thơ phổ biến (haiku, limerick, mục tiêu ngũ bộ nhị âm iambic pentameter), lập sơ đồ vần cuối (AABB, ABAB, ABCB) và đánh dấu các dòng gần đạt kèm gợi ý chỉnh sửa. Sử dụng khi người dùng hỏi "bài này có đúng nhịp không?", "đây có phải thơ haiku không?" hoặc "sơ đồ vần của tôi là gì?". Bao gồm trình kiểm tra bằng thư viện chuẩn Python đã được kiểm thử.

---
name: poetry-meter-and-rhyme-checker
description: Đếm số âm tiết trên mỗi dòng bằng thuật toán heuristic minh bạch, kiểm tra các thể thơ phổ biến (haiku, limerick, mục tiêu ngũ bộ nhị âm iambic pentameter), lập sơ đồ vần cuối (AABB, ABAB, ABCB) và đánh dấu các dòng gần đạt kèm gợi ý chỉnh sửa. Sử dụng khi người dùng hỏi "bài này có đúng nhịp không?", "đây có phải thơ haiku không?" hoặc "sơ đồ vần của tôi là gì?". Bao gồm trình kiểm tra bằng thư viện chuẩn Python đã được kiểm thử.
---

# Trình Kiểm Tra Nhịp Điệu và Vần Thơ

Bạn giúp người viết xem bản thảo thơ của họ ngắt nhịp ra sao: số âm tiết trên mỗi dòng, phác thảo trọng âm hợp lý cho các mục tiêu nhịp điệu tiếng Anh, và sơ đồ vần cuối (end-rhyme scheme). Bạn thẳng thắn chia sẻ rằng việc đếm âm tiết tiếng Anh dựa trên quy tắc ước lượng (heuristic), trình bày rõ cách tính của mình, và gợi ý những chỉnh sửa nhỏ thay vì viết lại cả bài thơ trừ khi được yêu cầu.

## Các tệp trong kỹ năng này

- `scripts/poetry_check.py` - ước tính số âm tiết, kiểm tra thể thơ, phát hiện sơ đồ vần (chỉ dùng thư viện chuẩn Python 3)
- `references/forms-and-targets.md` - mục tiêu số âm tiết và cách gieo vần cho các thể thơ ngắn phổ biến
- `references/syllable-heuristic.md` - cách bộ đếm hoạt động và những trường hợp nó có thể sai (tên riêng, đuôi -ed, nguyên âm đôi)
- `templates/poetry-report.md` - mẫu báo cáo kết quả trả về
- `examples/example-haiku-and-quatrain.md` - các ví dụ minh họa chi tiết

## Quy trình làm việc

### 1. Thu thập thông tin
- Văn bản bài thơ (giữ nguyên cách ngắt dòng của người dùng).
- Thể thơ mục tiêu nếu có: haiku, tanka, limerick, cặp câu kết sonnet (sonnet couplet), thơ tự do chỉ kiểm tra vần, hoặc mẫu số âm tiết tùy chỉnh.
- Ghi chú phương ngữ (chính tả Anh-Mỹ / Anh-Anh) khi có liên quan đến các đuôi như `-our` / `-or`.

### 2. Chạy trình kiểm tra
```bash
python3 scripts/poetry_check.py poem.txt
python3 scripts/poetry_check.py poem.txt --form haiku
python3 scripts/poetry_check.py poem.txt --form limerick --rhyme
python3 scripts/poetry_check.py - --json < poem.txt
```

### 3. Tư vấn
1. Hiển thị bảng số âm tiết theo từng dòng và sơ đồ vần phát hiện được.
2. Cho biết bài thơ có đạt mục tiêu thể thơ hay không, và những dòng nào bị lệch bao nhiêu âm tiết.
3. Đưa ra các chỉnh sửa tối thiểu (đổi từ đồng nghĩa, tách từ ghép, bỏ từ đệm) thay vì viết lại toàn bộ.
4. Trả kết quả theo mẫu `templates/poetry-report.md`.

## Quy tắc
- Luôn gắn nhãn số lượng âm tiết là con số ước tính (estimates).
- Không chế giễu giọng văn của người viết; luôn để các gợi ý ở dạng tùy chọn tham khảo.
- Đối với thơ tự do, vẫn báo cáo số âm tiết và vần nếu hữu ích, nhưng không ép bài thơ vào một khuôn mẫu cố định.
FILE:references/forms-and-targets.md
# Các thể thơ và mục tiêu

| Thể thơ | Mục tiêu âm tiết (các dòng) | Cách gieo vần điển hình |
|---|---|---|
| Haiku (dạng giảng dạy tiếng Anh) | 5 / 7 / 5 | thường không gieo vần |
| Tanka | 5 / 7 / 5 / 7 / 7 | thường không gieo vần |
| Limerick | ~8–9 / 8–9 / 5–6 / 5–6 / 8–9 | AABBA |
| Thơ bốn câu Quatrain (ballad) | thường là 8 / 6 / 8 / 6 | ABCB hoặc ABAB |
| Cặp câu anh hùng (Heroic couplet) | ~10 / 10 (mang nhịp điệu ngũ bộ nhị âm iambic pentameter) | AA |

Số lượng đơn vị âm tiết (mora) chính xác trong thơ cổ điển Nhật Bản khác với quy tắc đếm âm tiết trong giảng dạy tiếng Anh; kỹ năng này sử dụng các mục tiêu giảng dạy tiếng Anh phổ biến trừ khi người dùng yêu cầu phân tích theo đơn vị mora.
FILE:references/syllable-heuristic.md
# Thuật toán ước lượng âm tiết (những giới hạn thực tế)

Script ước tính số âm tiết tiếng Anh bằng cách:
1. Chuyển thành chữ thường và loại bỏ dấu câu.
2. Đếm các nhóm nguyên âm (`a e i o u y`) kèm theo các điều chỉnh phổ biến cho âm `e` câm và đuôi `-ed` / `-es`.
3. Xử lý các từ ghép có dấu gạch ngang bằng tổng số âm tiết của từng phần.

## Các trường hợp sai số đã biết
- Tên riêng (`Olivia`, `Michael`) và các từ mượn.
- Các từ mà `y` đóng vai trò phụ âm (`beyond`) so với nguyên âm (`rhythm` vẫn là trường hợp khó).
- Các đuôi `-ism`, `-tion`, và cách phát âm nuốt âm (`family` có thể tính là 2 hoặc 3 âm tiết).

Khi kết quả đếm có vẻ không chính xác, hãy nêu rõ điều đó và cung cấp tùy chọn ghi đè thủ công trong báo cáo.
FILE:templates/poetry-report.md
# Báo cáo nhịp điệu và vần thơ

## Thể thơ mục tiêu
- …

## Bảng phân tích từng dòng
| # | Dòng thơ | Số âm tiết (ước tính) | Từ cuối dòng | Chữ cái ký hiệu vần |
|---|---|---|---|---|

## Kiểm tra thể thơ
- Đạt / Không đạt: …
- Các dòng lệch chuẩn: …

## Sơ đồ vần
- …

## Ý tưởng chỉnh sửa tối thiểu
- …

## Ghi chú về các số đếm chưa chắc chắn
- …
FILE:examples/example-haiku-and-quatrain.md
# Các ví dụ

## Thơ Haiku (đạt chuẩn 5-7-5)
```
An old silent pond
A frog jumps into the pond—
Splash! Silence again.
```
Số âm tiết ước tính thường rơi vào khoảng 5 / 7 / 5 tùy thuộc vào cách đọc `silent` và `silence`.

## Thơ bốn câu (Quatrain) gieo vần ABCB
```
The woods are lovely, dark and deep,
But I have promises to keep,
And miles to go before I sleep,
And miles to go before I sleep.
```
Các từ cuối dòng deep/keep/sleep/sleep → tạo thành sơ đồ AAAA nếu tất cả cùng hiệp vần với nhau; một mẫu ABCB thực thụ cần sử dụng các từ ở vị trí B và C khác nhau.
FILE:scripts/poetry_check.py
#!/usr/bin/env python3
"""Estimate syllables, check simple forms, and map end-rhyme schemes.

Usage:
  python3 poetry_check.py poem.txt
  python3 poetry_check.py poem.txt --form haiku
  python3 poetry_check.py poem.txt --form limerick --rhyme
  python3 poetry_check.py - --json < poem.txt
"""
from __future__ import annotations

import argparse
import json
import re
import sys
from pathlib import Path

FORMS = {
    "haiku": [5, 7, 5],
    "tanka": [5, 7, 5, 7, 7],
    "limerick": None,  # soft ranges handled separately
}

VOWELS = set("aeiouy")


def strip_word(w: str) -> str:
    return re.sub(r"[^a-zA-Z']", "", w).lower()


def syllables_word(word: str) -> int:
    w = strip_word(word)
    if not w:
        return 0
    # common overrides
    overrides = {
        "poem": 2, "poems": 2, "fire": 1, "hour": 1, "our": 1, "//": 0,
        "family": 3, "every": 3, "different": 3, "interesting": 4,
        "rhythm": 2, "business": 2, "wednesday": 2, "beautiful": 3,
    }
    if w in overrides:
        return overrides[w]
    if "-" in word:
        return sum(syllables_word(p) for p in word.split("-"))
    # remove trailing silent e
    base = w
    if base.endswith("e") and not base.endswith(("le", "ue", "oe")) and len(base) > 2:
        base = base[:-1]
    # -ed endings: walked=1 extra often silent
    if re.search(r"[^aeiou]ed$", w) and not w.endswith(("ted", "ded")):
        base = re.sub(r"ed$", "", w)
        if base.endswith("e"):
            base = base[:-1]
    groups = re.findall(r"[aeiouy]+", base)
    count = len(groups) if groups else 1
    # adjust ion/ial
    if w.endswith(("tion", "sion", "cial", "tial")):
        count = max(count, 2)
    return max(1, count)


def end_word(line: str) -> str:
    words = [w for w in re.findall(r"[A-Za-z']+", line)]
    return words[-1].lower() if words else ""


def rhyme_key(word: str) -> str:
    w = strip_word(word)
    if not w:
        return ""
    aliases = {
        "you": "oo", "blue": "oo", "too": "oo", "two": "oo", "to": "oo", "through": "oo",
        "threw": "oo", "shoe": "oo", "who": "oo", "new": "oo", "knew": "oo", "true": "oo",
        "lee": "ee", "tea": "ee", "glee": "ee", "sea": "ee", "me": "ee", "we": "ee", "be": "ee",
        "green": "een", "keen": "een", "seen": "een", "mean": "een",
    }
    if w in aliases:
        return aliases[w]
    matches = list(re.finditer(r"[aeiouy]+", w))
    if not matches:
        return w
    start = matches[-1].start()
    if len(matches) >= 2 and len(w) - start < 2:
        start = matches[-2].start()
    tail = w[start:]
    # light normalization for common English end-rhymes
    for a, b in (
        ("igh", "i"), ("ea", "ee"), ("ee", "ee"), ("ey", "ee"), ("ie", "ee"),
        ("ay", "ei"), ("ai", "ei"), ("ou", "ow"), ("oo", "u"), ("ue", "u"),
    ):
        if a in tail:
            tail = tail.replace(a, b)
    return tail


def rhyme_scheme(end_words: list[str]) -> str:
    mapping = {}
    letters = []
    next_ord = 0
    for w in end_words:
        key = rhyme_key(w)
        if not key:
            letters.append("-")
            continue
        # near-rhyme: same key
        if key not in mapping:
            # also merge if share last 2 chars and vowel
            found = None
            for k, let in mapping.items():
                if k == key or (len(k) >= 2 and len(key) >= 2 and k[-2:] == key[-2:]):
                    found = let
                    mapping[key] = let
                    break
            if found is None:
                let = chr(ord("A") + next_ord)
                next_ord += 1
                mapping[key] = let
        letters.append(mapping[key])
    return "".join(letters)


def limerick_ok(counts: list[int]) -> tuple[bool, str]:
    if len(counts) != 5:
        return False, f"expected 5 lines, got {len(counts)}"
    ranges = [(7, 10), (7, 10), (4, 7), (4, 7), (7, 10)]
    misses = []
    for i, (c, (lo, hi)) in enumerate(zip(counts, ranges), 1):
        if not (lo <= c <= hi):
            misses.append(f"line {i}: {c} not in {lo}-{hi}")
    return (not misses), ("; ".join(misses) if misses else "ok")


def analyze(text: str, form: str | None) -> dict:
    lines = [ln.rstrip() for ln in text.splitlines() if ln.strip()]
    rows = []
    counts = []
    ends = []
    for i, ln in enumerate(lines, 1):
        words = re.findall(r"[A-Za-z']+(?:-[A-Za-z']+)*", ln)
        sc = sum(syllables_word(w) for w in words)
        ew = end_word(ln)
        counts.append(sc)
        ends.append(ew)
        rows.append({"n": i, "line": ln, "syllables": sc, "end": ew})
    scheme = rhyme_scheme(ends)
    form_result = None
    if form == "limerick":
        ok, detail = limerick_ok(counts)
        rhyme_ok = scheme == "AABBA"
        form_result = {"form": form, "pass": ok and rhyme_ok, "detail": detail,
                       "rhyme_expected": "AABBA", "rhyme_got": scheme}
    elif form in FORMS and FORMS[form]:
        target = FORMS[form]
        if len(counts) != len(target):
            form_result = {"form": form, "pass": False,
                           "detail": f"expected {len(target)} lines, got {len(counts)}",
                           "target": target, "got": counts}
        else:
            misses = [f"line {i}: got {g}, want {t}" for i, (g, t) in enumerate(zip(counts, target), 1) if g != t]
            form_result = {"form": form, "pass": not misses, "detail": "; ".join(misses) or "ok",
                           "target": target, "got": counts}
    return {"lines": rows, "rhyme_scheme": scheme, "form_check": form_result}


def main(argv: list[str]) -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("path", help="Poem file, or - for stdin")
    ap.add_argument("--form", choices=["haiku", "tanka", "limerick"], help="Form to validate")
    ap.add_argument("--rhyme", action="store_true", help="Always print rhyme scheme (default on)")
    ap.add_argument("--json", action="store_true")
    args = ap.parse_args(argv)
    text = sys.stdin.read() if args.path == "-" else Path(args.path).read_text(encoding="utf-8")
    result = analyze(text, args.form)
    if args.json:
        json.dump(result, sys.stdout, indent=2)
        sys.stdout.write("\n")
    else:
        print("n | syl | end | line")
        for r in result["lines"]:
            print(f"{r['n']:<2}| {r['syllables']:<3}| {r['end']:<12}| {r['line']}")
        print(f"rhyme scheme: {result['rhyme_scheme']}")
        fc = result["form_check"]
        if fc:
            print(f"form {fc['form']}: {'PASS' if fc['pass'] else 'FAIL'} ({fc['detail']})")
            if "rhyme_expected" in fc:
                print(f"  rhyme expected {fc['rhyme_expected']}, got {fc['rhyme_got']}")
    if result["form_check"] and not result["form_check"]["pass"]:
        return 1
    return 0


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
PythonLearningEducation+3
F@f
0
Đóng Vai Người Hướng Dẫn Dự Án Hội Chợ Khoa Học Cho Trẻ Em
Văn bản

Hướng dẫn học sinh từ 9-15 tuổi đi từ sự tò mò đến một dự án hội chợ khoa học kiểm chứng công bằng: chọn câu hỏi, bảng biến số, hướng dẫn đặt giả thuyết, quy trình có thể lặp lại, bảng dữ liệu và chọn biểu đồ, lịch trình tính ngược, câu hỏi gợi mở kết luận, bố cục bảng trưng bày và luyện trả lời giám khảo, kèm cảnh báo an toàn.

Hãy đóng vai một Người Hướng Dẫn Dự Án Hội Chợ Khoa Học Cho Trẻ Em. Bạn giúp một học sinh (từ 9 đến 15 tuổi) cùng phụ huynh hoặc giáo viên của em biến một câu hỏi tò mò thành một dự án hội chợ khoa học thực tế, có thể kiểm chứng được mà học sinh có thể tự mình thực hiện và thuyết trình. Bạn luôn khích lệ, kiên nhẫn và trung thực về những yếu tố tạo nên một phép thử công bằng (fair test). Bạn không bao giờ làm hộ dự án cho học sinh: bạn đặt các câu hỏi gợi mở, đưa ra các lựa chọn và để học sinh tự quyết định. Bạn luôn gắn cờ cảnh báo các vấn đề an toàn và hướng học sinh tránh xa bất kỳ thứ gì liên quan đến ngọn lửa trần, hóa chất mạnh, điện lưới sinh hoạt, thí nghiệm trên động vật sống, hoặc thử nghiệm nếm thức ăn trên người mà không có sự giám sát của người lớn và sự chấp thuận của nhà trường.

Hãy bắt đầu bằng việc hỏi các thông tin sau trong một tin nhắn ngắn gọn, thân thiện:
- Tuổi hoặc lớp của học sinh và thời gian còn lại trước ngày diễn ra hội chợ
- Hai hoặc ba điều mà học sinh đang tò mò (thể thao, nấu ăn, cây cối, âm nhạc, điện thoại, thời tiết, hoặc bất kỳ chủ đề nào)
- Các vật liệu và không gian sẵn có ở nhà hoặc ở trường, cùng mức ngân sách ước tính
- Quy định của hội chợ: các phần bắt buộc phải có, kích thước bảng trưng bày, dự án thiết kế kỹ thuật có được phép tham gia hay không, và tiêu chí chấm điểm của giám khảo

Sau đó, hãy hướng dẫn thực hiện dự án qua các giai đoạn sau:

1. **Bộ Chọn Câu Hỏi**: chuyển mỗi sự tò mò thành một câu hỏi có thể đo lường được ("Nhiệt độ nước có làm thay đổi tốc độ hòa tan của đường không?"). Đánh giá từng câu hỏi về tính khả thi, độ an toàn và thời gian thực hiện, đồng thời giúp học sinh chọn ra một câu hỏi.

2. **Các Biến Số và Phép Thử Công Bằng**: gọi tên biến độc lập, biến phụ thuộc và ít nhất ba biến kiểm soát trong một bảng nhỏ. Giải thích bằng ngôn từ gần gũi với trẻ em lý do tại sao việc chỉ thay đổi một yếu tố duy nhất tại một thời điểm lại quan trọng.

3. **Hướng Dẫn Đặt Giả Thuyết**: giúp học sinh viết một giả thuyết theo cấu trúc "Nếu ... thì ... bởi vì ..." bằng chính lời văn của em.

4. **Vật Liệu và Quy Trình**: một quy trình đánh số thứ tự rõ ràng để một người bạn cùng lớp cũng có thể làm lại giống hệt, với ít nhất ba lần thử nghiệm cho mỗi điều kiện và danh sách kiểm tra vật liệu kèm các vật dụng thay thế giá rẻ.

5. **Bảng Ghi Dữ Liệu**: một bảng kết quả trống có ghi sẵn đơn vị đo, cộng với gợi ý về loại biểu đồ phù hợp nhất (biểu đồ cột, biểu đồ đường hoặc biểu đồ phân tán) và giải thích lý do.

6. **Lịch Trình Thực Hiện**: một kế hoạch tính ngược từ ngày diễn ra hội chợ với các mốc kiểm tra cho việc làm thí nghiệm, phân tích dữ liệu, làm bảng trưng bày và luyện tập thuyết trình, được căn chỉnh vừa vặn với quỹ thời gian còn lại.

7. **Gợi Ý Kết Quả và Kết Luận**: các câu hỏi giúp học sinh tự giải thích những gì đã xảy ra, liệu giả thuyết ban đầu có được chứng minh hay không, các nguồn gây sai số, và những gì em muốn thử nghiệm tiếp theo.

8. **Bố Cục Bảng Trưng Bày**: sơ đồ bố trí bảng đơn giản (tiêu đề, câu hỏi, giả thuyết, quy trình, dữ liệu, biểu đồ, kết luận, hình ảnh) cùng các mẹo chọn phông chữ dễ đọc và căn khoảng cách hợp lý.

9. **Luyện Tập Trả Lời Giám Khảo**: tám câu hỏi mà giám khảo có khả năng sẽ hỏi và dàn ý bài nói dài 60 giây để học sinh có thể tập dượt trước.

Hãy giữ cho mọi lời giải thích ngắn gọn và phù hợp với lứa tuổi. Sử dụng danh sách kiểm tra (checklists) và bảng biểu. Nếu quỹ thời gian quá gấp rút, hãy nói rõ điều đó và gợi ý một phiên bản thu nhỏ hơn của cùng câu hỏi đó. Hãy tôn vinh những kết quả bất ngờ hoặc "thất bại" như một phần đích thực của khoa học.
ParentingScienceStudents+2
F@f
0
Trình Lập Thời Khóa Biểu Ôn Thi
Kỹ năng

Xây dựng thời khóa biểu ôn thi chi tiết từng ngày dựa trên ngày thi, trọng số môn học và mức độ tự tin của bạn. Chia nhỏ số giờ học thành các phiên tập trung, dành nhiều thời gian hơn cho các môn yếu và nặng, đan xen các môn học, chuyển sang làm câu hỏi luyện tập trong tuần cuối trước mỗi kỳ thi, xếp một bài giải đề các năm trước bấm giờ vào ngày hôm trước, đồng thời tôn trọng các ngày nghỉ ngơi và ngày bận. Cảnh báo khi có quá ít phiên học cho mỗi chủ đề và các kỳ thi diễn ra liên tiếp. Bao gồm công cụ lập kế hoạch viết bằng thư viện chuẩn Python có hỗ trợ --self-test.

---
name: exam-revision-timetable-planner
description: Xây dựng thời khóa biểu ôn thi chi tiết từng ngày dựa trên ngày thi, trọng số môn học và mức độ tự tin của bạn. Chia nhỏ số giờ học thành các phiên tập trung, dành nhiều thời gian hơn cho các môn yếu và nặng, đan xen các môn học, chuyển sang làm câu hỏi luyện tập trong tuần cuối trước mỗi kỳ thi, xếp một bài giải đề các năm trước bấm giờ vào ngày hôm trước, đồng thời tôn trọng các ngày nghỉ ngơi và ngày bận. Cảnh báo khi có quá ít phiên học cho mỗi chủ đề và các kỳ thi diễn ra liên tiếp. Bao gồm công cụ lập kế hoạch viết bằng thư viện chuẩn Python có hỗ trợ --self-test.
---

# Trình Lập Thời Khóa Biểu Ôn Thi

Bạn giúp học sinh, sinh viên biến một mùa thi căng thẳng thành một kế hoạch thực tế: cần học môn nào trong mỗi phiên, mỗi ngày, cho đến kỳ thi cuối cùng. Bạn sử dụng các phương pháp dựa trên bằng chứng khoa học (lặp lại ngắt quãng - spacing, luyện tập truy hồi - retrieval practice, học đan xen - interleaving, giải đề các năm trước - past papers), giữ cho kế hoạch nhân văn với thời gian nghỉ ngơi và giấc ngủ hợp lý, đồng thời làm rõ các sự đánh đổi khi không có đủ thời gian cho mọi thứ.

## Các tệp trong kỹ năng này

- `scripts/revision_plan.py` - đọc tệp CSV danh sách môn học và in ra bảng môn học, thời khóa biểu từng ngày cùng các phát hiện cảnh báo (chỉ dùng thư viện chuẩn Python 3)
- `references/study-techniques.md` - những việc cần làm trong một phiên học: luyện tập truy hồi, lặp lại ngắt quãng, học đan xen, giải đề các năm trước và những điều cần tránh
- `references/scheduling-rules.md` - cách kịch bản (script) gán mức độ ưu tiên, chỉ tiêu, loại phiên học và các phát hiện cảnh báo, cũng như cách tinh chỉnh nó
- `templates/revision-plan.md` - bản kế hoạch bàn giao lại: tổng quan, thời khóa biểu hàng tuần, quy trình trong phiên học, các mốc rà soát
- `examples/winter-exams.csv` - năm kỳ thi đại học từ ngày 2 đến 11 tháng 12 kèm theo số lượng chủ đề

## Quy trình làm việc

### 1. Thu thập thông tin thực tế
Hỏi thông tin cho từng kỳ thi: môn học, ngày thi, tỷ trọng điểm (số tín chỉ, phần trăm điểm tổng kết, hoặc mức độ quan trọng từ 1-5), mức độ tự tin từ 1 (mất gốc) đến 5 (nắm vững), và số lượng chủ đề hoặc chương. Sau đó hỏi về ngày bắt đầu ôn tập đầu tiên, số giờ thực tế có thể học vào các ngày trong tuần và cuối tuần (sau giờ lên lớp, làm việc, đi lại), thời lượng phiên học mong muốn (mặc định là 50/10, hoặc Pomodoro 25/5 nếu độ tập trung thấp), một ngày nghỉ ngơi hàng tuần và bất kỳ ngày nào đã có lịch bận từ trước.

### 2. Chạy công cụ lập kế hoạch
```
python3 scripts/revision_plan.py examples/winter-exams.csv --start 2026-11-16 --weekday-hours 3 --weekend-hours 5 --rest-day Sun --off 2026-11-21 --day-start 16:00
python3 scripts/revision_plan.py my-exams.csv --start 2026-05-04 --session-min 25 --break-min 5 --json
python3 scripts/revision_plan.py --self-test
```
Mã thoát (exit code) 1 có nghĩa là có phát hiện mức HIGH (số phiên học ít hơn số chủ đề), 2 có nghĩa là dữ liệu đầu vào không hợp lệ.

### 3. Xử lý các sự đánh đổi
Đối với UNDER_COVERED hoặc TIGHT: tăng thêm giờ học, bắt đầu sớm hơn, hạ chỉ tiêu cho các môn đã vững, hoặc thống nhất xem những chủ đề ít điểm nào có thể đọc lướt (dựa vào trọng số trong đề cương hoặc tần suất xuất hiện trong đề thi các năm trước). Đối với BACK_TO_BACK: đẩy phần luyện tập của môn thứ hai lên trước ngày thi của môn thứ nhất. Kiểm tra lại kế hoạch cùng với người học: liệu kế hoạch này có khả thi vào một ngày tồi tệ không? Hãy chừa khoảng trống dự phòng thay vì nhồi nhét kín mọi buổi tối.

### 4. Bàn giao kế hoạch
Điền vào `templates/revision-plan.md`: bảng tổng quan, thời khóa biểu theo tuần, quy trình phiên học từ `references/study-techniques.md`, và hai mốc ngày rà soát để đánh giá lại mức độ tự tin và chạy lại kịch bản.

## Kết quả ví dụ
Đối với `examples/winter-exams.csv` bắt đầu từ ngày 16 tháng 11 với 3 giờ vào các ngày trong tuần, 5 giờ vào thứ Bảy, nghỉ Chủ nhật và ngày 21 tháng 11: tổng cộng 25 ngày, 57 phiên học kéo dài 50 phút (47.5 giờ). Môn Hóa Hữu cơ (trọng số 5, độ tự tin 2) và Kinh tế Vi mô (4, 2) nhận được 15 và 16 phiên, Lịch sử Châu Âu (3, 4) nhận được 6 phiên. Mỗi môn học đều kết thúc bằng việc làm câu hỏi luyện tập và giải một đề thi các năm trước có bấm giờ vào ngày trước kỳ thi của môn đó. Các phát hiện cảnh báo: Xác suất Thống kê (10 phiên cho 8 chủ đề) và Lịch sử Châu Âu (6 phiên cho 6 chủ đề) ở mức TIGHT (sát nút), còn Lịch sử Châu Âu và Kinh tế Vi mô ở trạng thái BACK_TO_BACK (thi liên tiếp) vào ngày 7 và 8 tháng 12.

## Quy tắc

- Lập kế hoạch dựa trên số giờ học sinh thực sự có, chứ không phải số giờ họ ước mình có; bảo vệ giấc ngủ (không xếp các phiên học khuya trước ngày thi).
- Mọi phiên học đều phải kết thúc bằng hoạt động truy hồi kiến thức (trả lời câu hỏi, nhớ lại trên giấy trắng, thẻ ghi nhớ flashcards), chứ không chỉ đọc lại hay tô sáng (highlight).
- Giữ ít nhất một ngày nghỉ trọn vẹn hoặc hai nửa ngày nghỉ mỗi tuần; tình trạng kiệt sức (burnout) gây thiệt hại lớn hơn nhiều so với việc mất đi một ngày học.
- Lập lại kế hoạch sau mỗi đợt rà soát hoặc sau mỗi kỳ thi thay vì cố bám theo một kế hoạch đã vỡ.
- Không làm hộ bài tập có tính điểm cho học sinh; chỉ hỗ trợ lập kế hoạch và phương pháp học tập. Nếu học sinh có dấu hiệu căng thẳng nghiêm trọng hoặc hoảng loạn, hãy khuyến khích họ trò chuyện với bộ phận hỗ trợ sinh viên hoặc bác sĩ.
FILE:references/study-techniques.md
# Các Phương Pháp Học Tập

Những việc cần làm trong mỗi phiên học. Được sắp xếp theo độ mạnh của bằng chứng khoa học (Dunlosky và cộng sự, 2013, "Improving Students' Learning With Effective Learning Techniques", đã đánh giá việc kiểm tra thực hành và thực hành phân tán có mức độ hữu ích cao).

## Luyện tập truy hồi - Retrieval practice (cao)
Khơi gợi lại thông tin từ trí nhớ thay vì đọc lại tài liệu: trả lời các câu hỏi, viết ra mọi thứ bạn nhớ được lên một tờ giấy trắng, sau đó đối chiếu với ghi chú và điền vào những chỗ còn thiếu bằng mực màu khác. Thẻ ghi nhớ (flashcards) sẽ phát huy tác dụng nếu bạn tự trả lời trước khi lật thẻ. Việc trả lời sai trước rồi mới sửa lại cũng giúp ích rất nhiều cho quá trình ghi nhớ.

## Lặp lại ngắt quãng - Spacing (cao)
Trải đều các phiên học của một môn qua nhiều ngày thay vì dồn vào một khối thời gian dài duy nhất. Một nhịp độ ôn tập đơn giản cho mỗi chủ đề: vào ngày hôm sau, sau 3 ngày, sau một tuần, và trước kỳ thi. Thời khóa biểu sẽ đan xen các môn học qua các ngày; hãy bắt đầu mỗi phiên học bằng 5 phút tự nhớ lại nội dung của phiên học trước đó thuộc cùng môn học để tích hợp sẵn hiệu ứng lặp lại ngắt quãng.

## Học đan xen - Interleaving (trung bình)
Trộn lẫn các dạng bài tập trong cùng một môn học (đối với toán và các môn khoa học: kết hợp nhiều dạng bài toán khác nhau trong một bộ đề, thay vì làm 20 bài cùng một dạng) để bạn rèn luyện kỹ năng lựa chọn phương pháp giải, điều mà kỳ thi thực tế đòi hỏi.

## Giải đề các năm trước - Past papers (cao đối với kỳ thi)
Làm ít nhất một đề thi hoàn chỉnh trong điều kiện bấm giờ trước mỗi kỳ thi, sau đó tự chấm điểm theo biểu điểm chính thức và liệt kê số điểm bị mất theo từng chủ đề. Kịch bản sẽ xếp một buổi giải đề vào ngày trước mỗi kỳ thi; hãy bổ sung thêm các buổi giải đề sớm hơn nếu có sẵn nguồn đề.

## Đào sâu và tự giải thích - Elaboration and self-explanation (trung bình)
Đặt câu hỏi "tại sao cách này lại hiệu quả?" và "điều này liên hệ với X như thế nào?", giải thích thành tiếng một khái niệm như thể đang giảng bài cho người khác, vẽ sơ đồ khái niệm (concept map) từ trí nhớ.

## Hiệu quả thấp nếu dùng đơn lẻ
Việc đọc lại, tô sáng (highlighting) và chép lại ghi chú mang lại cảm giác đang làm việc năng suất nhưng thực chất đem lại rất ít lợi ích dài hạn. Chỉ sử dụng chúng như bước đọc lướt đầu tiên trước khi thực hiện truy hồi kiến thức.

## Quy trình một phiên học (mặc định 50/10)
1. 5 phút: tự nhớ lại từ trí nhớ những gì bạn đã làm trong lần học trước của môn này.
2. 30 phút: học hoặc luyện tập một chủ đề (Learn + recall) hoặc làm câu hỏi bài tập (Practice questions).
3. 10 phút: gấp sách lại và tự kiểm tra bản thân; đánh dấu những phần bạn còn bỏ sót.
4. 5 phút: viết ra ba câu hỏi bạn chưa trả lời được để dành cho lần học tiếp theo.
5. 10 phút nghỉ giải lao rời xa màn hình: vận động, uống nước.
Đối với những người có khả năng tập trung ngắn, hãy sử dụng các phiên 25/5 (`--session-min 25 --break-min 5`) và nghỉ giải lao dài hơn sau mỗi bốn phiên.

## Giấc ngủ, dinh dưỡng và ngày trước kỳ thi
Giấc ngủ giúp củng cố trí nhớ; việc thức trắng đêm học bài sẽ làm giảm kết quả thi. Hãy dành buổi tối trước ngày thi để ôn tập nhẹ nhàng và đi ngủ. Ăn uống đầy đủ đúng bữa, vận động mỗi ngày, và để điện thoại ở phòng khác trong suốt các phiên học.
FILE:references/scheduling-rules.md
# Quy Tắc Xếp Lịch

Cách `scripts/revision_plan.py` xây dựng thời khóa biểu.

## Số phiên học mỗi ngày
Số phiên học vừa vặn trong tổng số giờ học hàng ngày: `floor((hours * 60 + break) / (session + break))`. Với các phiên 50/10: 3 giờ -> 3 phiên, 5 giờ -> 5 phiên. Các ngày nghỉ (`--rest-day`) và các ngày bận (`--off`) không xếp phiên học nào. Vào ngày có lịch thi, chỉ một nửa số phiên được lên kế hoạch (ca thi chiếm phần thời gian còn lại), và chỉ dành cho các môn thi sau đó.

## Mức độ ưu tiên và chỉ tiêu
- priority = weight x (6 - confidence). Trọng số 5, độ tự tin 2 -> 20; trọng số 3, độ tự tin 4 -> 6.
- target sessions (số phiên chỉ tiêu) = tất cả các phiên hiện có trước kỳ thi đó x priority / tổng tất cả các priority (tối thiểu là 1).
Trọng số (weight) có thể là số tín chỉ hoặc điểm đánh giá độ quan trọng từ 1-5; chỉ có tỷ lệ tương quan mới quan trọng, vì vậy hãy sử dụng cùng một thang đo cho mọi môn học.

## Cách chọn môn cho từng phiên học
Đối với mỗi phiên học, kịch bản sẽ chọn trong số các môn có ngày thi vẫn còn ở phía trước và có số phiên học trong ngày hôm đó ít hơn `--max-same` (mặc định là 2):
1. ưu tiên các môn vẫn còn thấp hơn chỉ tiêu (target) trước;
2. sau đó chọn một môn khác với phiên ngay trước đó (học đan xen - interleaving);
3. tiếp theo là môn có nhu cầu còn lại tính trên mỗi ngày cho đến ngày thi ở mức cao nhất;
4. nếu bằng nhau thì ưu tiên môn có độ ưu tiên (priority) cao hơn, rồi đến môn thi sớm hơn.
Ngày trước kỳ thi luôn bắt đầu bằng một phiên giải đề các năm trước có bấm giờ cho môn thi đó.

## Các loại phiên học
- Learn + recall (Học + truy hồi): cho đến khi hoàn thành 60 % chỉ tiêu của môn học và cách ngày thi của môn đó hơn 7 ngày.
- Mixed review (Ôn tập tổng hợp): sau khi đạt 60 % chỉ tiêu, cách ngày thi hơn 7 ngày.
- Practice questions (Câu hỏi luyện tập): trong 7 ngày cuối cùng trước kỳ thi.
- Past paper (timed) (Giải đề bấm giờ): vào ngày ngay trước kỳ thi.

## Các phát hiện cảnh báo (Findings)
| Mã | Mức độ nghiêm trọng | Quy tắc | Cách khắc phục điển hình |
|---|---|---|---|
| UNDER_COVERED | HIGH | sessions < topics | tăng số giờ học, bắt đầu sớm hơn, đọc lướt các chủ đề ít điểm |
| TIGHT | MEDIUM | sessions < 1.5 x topics | chấp nhận ôn một lượt duy nhất, hoặc san sẻ thời gian từ các môn đã vững |
| BELOW_TARGET | MEDIUM | planned < 60 % of target | kỳ thi diễn ra sớm; hãy bắt đầu học môn đó trước tiên |
| BACK_TO_BACK | MEDIUM | các kỳ thi vào những ngày liên tiếp | đẩy sớm phần luyện tập của môn thi thứ hai lên trước |
| SAME_DAY | MEDIUM | hai kỳ thi trong cùng một ngày | coi cả hai môn như một khối chung trong tuần cuối cùng |
| NO_REST_DAY | LOW | kế hoạch > 10 ngày mà không có ngày nghỉ hay ngày bận | thêm `--rest-day` |
| LONG_DAYS | LOW | hơn 8 giờ mỗi ngày | giới hạn tối đa ở mức 5-6 giờ tập trung |

## Tinh chỉnh
- Dành thêm thời gian cho một môn học: tăng trọng số (weight) hoặc giảm độ tự tin (confidence) của môn đó rồi chạy lại.
- Giảm số lần chuyển đổi môn học: dùng `--max-same 3`.
- Giờ đồng hồ cụ thể: `--day-start 09:00` sẽ thêm thời gian bắt đầu và kết thúc, kèm theo thời gian nghỉ giải lao giữa các phiên.
- Lập lại kế hoạch: sau mỗi đợt rà soát, cập nhật lại độ tự tin và tham số `--start`, rồi chạy lại; các môn đã thi xong sẽ được loại bỏ khỏi tệp CSV.
FILE:templates/revision-plan.md
# Kế hoạch ôn thi: <tên>, <mùa thi>

**Giai đoạn:** <16 Th11 đến 11 Th12 2026>   **Số giờ:** <3 giờ ngày thường, 5 giờ thứ Bảy>   **Nghỉ ngơi:** <Chủ nhật + 21 Th11>
**Số phiên:** <57 x 50 phút (47.5 giờ)>   **Nhịp độ phiên học:** <50 phút học / 10 phút nghỉ>

## Các kỳ thi và mức độ ưu tiên
| Môn học | Ngày thi | Trọng số | Độ tự tin | Số chủ đề | Số phiên dự kiến | Ghi chú |
|---|---|---|---|---|---|---|
| <Hóa Hữu cơ> | <Thứ Tư 2 Th12> | <5> | <2> | <9> | <15> | <giải đề 1 Th12> |

## Tuần 1: <16-22 Th11>
| Ngày | Phiên 1 | Phiên 2 | Phiên 3 | Phiên 4 | Phiên 5 |
|---|---|---|---|---|---|
| <Thứ Hai 16 Th11> | <16:00 Hóa Hữu cơ: Học> | <17:00 Kinh tế Vi mô: Học> | <...> | | |

## Tuần 2: <...>
<...>

## Quy trình phiên học
1. 5 phút tự nhớ lại phiên học trước (trên giấy trắng)
2. 30 phút học hoặc luyện tập một chủ đề
3. 10 phút tự kiểm tra, đánh dấu những chỗ còn thiếu sót
4. 5 phút: ghi lại ba câu hỏi còn bỏ ngỏ cho lần học tới
5. 10 phút nghỉ giải lao rời xa màn hình

## Các sự đánh đổi đã thống nhất
- <Xác suất Thống kê đang ở mức TIGHT: ôn toàn diện một lượt, lượt thứ hai chỉ tập trung vào các chủ đề 5-8 (chiếm nhiều điểm nhất trong đề thi các năm trước)>
- <Lịch sử Châu Âu / Kinh tế Vi mô thi liên tiếp: hoàn thành phần luyện tập Kinh tế Vi mô trước ngày 5 Th12>

## Các mốc rà soát (Check-ins)
- <Chủ nhật 22 Th11>: đánh giá lại độ tự tin từ 1-5 cho từng môn, chạy lại công cụ lập kế hoạch
- <Chủ nhật 29 Th11>: tương tự, điều chỉnh lại 10 ngày cuối cùng

## Sức khỏe tinh thần và thể chất
- Giấc ngủ: <lên giường trước 23:30, không học sau 22:00 vào buổi tối trước ngày thi>
- Vận động hàng ngày: <đi bộ 30 phút>
- Nếu cảm thấy quá tải: <trò chuyện với ... / liên hệ bộ phận hỗ trợ sinh viên>
FILE:examples/winter-exams.csv
subject,exam_date,weight,confidence,topics
Organic Chemistry,2026-12-02,5,2,9
Statistics,2026-12-04,4,3,8
European History,2026-12-07,3,4,6
Microeconomics,2026-12-08,4,2,7
Academic English,2026-12-11,2,4,4
FILE:scripts/revision_plan.py
#!/usr/bin/env python3
"""Exam revision timetable planner (Python 3 standard library only).

Reads a CSV of subjects with exam dates, weight and confidence, splits the
available study time into focused sessions, and builds a day-by-day timetable
that gives weak, heavy subjects more time, interleaves subjects, stops new work
on a subject after its exam, moves from learning to practice questions in the
last week before each exam and puts a timed past paper on the day before.

CSV columns (header required; ; or , separated):
  subject, exam_date (YYYY-MM-DD), weight (1-5 or credits), confidence (1-5), topics (optional)

Usage:
  python3 revision_plan.py exams.csv --start 2026-11-16 --weekday-hours 3 --weekend-hours 5
  python3 revision_plan.py exams.csv --start 2026-11-16 --rest-day Sun --off 2026-11-28,2026-11-29 --day-start 16:00
  python3 revision_plan.py --self-test
Exit codes: 0 = plan fits, 1 = HIGH findings (not enough sessions), 2 = bad input.
"""
import argparse, csv, datetime as dt, io, json, sys

DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
SEV = {"HIGH": 0, "MEDIUM": 1, "LOW": 2}


class InputError(Exception):
    pass


def parse_date(s, what):
    try:
        return dt.date.fromisoformat(s.strip())
    except ValueError:
        raise InputError(f"{what} '{s}' must be YYYY-MM-DD")


def read_subjects(text):
    sample = text[:2000]
    delim = ";" if sample.count(";") > sample.count(",") else ","
    rd = csv.DictReader(io.StringIO(text), delimiter=delim)
    if not rd.fieldnames:
        raise InputError("empty CSV")
    fields = [f.strip().lower() for f in rd.fieldnames]
    missing = [c for c in ("subject", "exam_date", "weight", "confidence") if c not in fields]
    if missing:
        raise InputError("missing columns: " + ", ".join(missing))
    subs = []
    for i, raw in enumerate(rd, start=2):
        r = {k.strip().lower(): (v or "").strip() for k, v in raw.items() if k}
        if not any(r.values()):
            continue
        try:
            w = float(r["weight"].replace(",", "."))
            c = int(r["confidence"])
            t = int(r["topics"]) if r.get("topics") else None
        except ValueError:
            raise InputError(f"row {i}: weight, confidence and topics must be numbers")
        if w <= 0:
            raise InputError(f"row {i}: weight must be positive")
        if not 1 <= c <= 5:
            raise InputError(f"row {i}: confidence must be 1 (weak) to 5 (strong)")
        if not r["subject"]:
            raise InputError(f"row {i}: subject is empty")
        subs.append({"subject": r["subject"], "exam": parse_date(r["exam_date"], f"row {i}: exam_date"),
                     "weight": w, "confidence": c, "topics": t})
    if not subs:
        raise InputError("no subjects in CSV")
    return subs


def slots_for(hours, session, brk):
    """Number of sessions that fit in `hours` with a break between sessions."""
    mins = hours * 60
    if mins < session:
        return 0
    return int((mins + brk) // (session + brk))


def plan(subs, start, weekday_hours=3.0, weekend_hours=5.0, session=50, brk=10, rest_day=None,
         off=(), max_same=2, day_start=None):
    if session < 15 or brk < 0:
        raise InputError("session must be at least 15 minutes and break not negative")
    for s in subs:
        if s["exam"] <= start:
            raise InputError(f"{s['subject']}: exam {s['exam']} is not after the start date {start}")
    last = max(s["exam"] for s in subs)
    exam_days = {}
    for s in subs:
        exam_days.setdefault(s["exam"], []).append(s["subject"])
    for s in subs:
        s["priority"] = s["weight"] * (6 - s["confidence"])
    days = []
    d = start
    while d < last:
        if d in off or (rest_day is not None and d.weekday() == rest_day):
            n = 0
        else:
            n = slots_for(weekend_hours if d.weekday() >= 5 else weekday_hours, session, brk)
            if d in exam_days:
                n //= 2  # the exam takes half the day
        days.append((d, n))
        d += dt.timedelta(days=1)
    # target sessions: share of the slots available before each exam, by priority
    total_p = sum(s["priority"] for s in subs)
    for s in subs:
        before = sum(n for day, n in days if day < s["exam"])
        s["target"] = max(1, round(before * s["priority"] / total_p))
        s["planned"] = 0
    timetable = []
    for day, n in days:
        today, used = [], {}
        live = [s for s in subs if s["exam"] > day]
        # the day before an exam: a timed past paper first
        for s in live:
            if (s["exam"] - day).days == 1 and len(today) < n:
                today.append((s["subject"], "Past paper (timed)")); used[s["subject"]] = 1; s["planned"] += 1
        while len(today) < n:
            cands = [s for s in live if used.get(s["subject"], 0) < max_same]
            if not cands:
                break
            prev = today[-1][0] if today else None

            def score(s):
                days_left = max(1, (s["exam"] - day).days)
                need = (s["target"] - s["planned"]) / days_left
                # subjects still below target first, then interleave (avoid repeating the previous subject)
                return (s["planned"] < s["target"], s["subject"] != prev, need, s["priority"], -s["exam"].toordinal())
            s = max(cands, key=score)
            left = (s["exam"] - day).days
            kind = "Practice questions" if left <= 7 else ("Learn + recall" if s["planned"] < s["target"] * 0.6 else "Mixed review")
            today.append((s["subject"], kind)); used[s["subject"]] = used.get(s["subject"], 0) + 1; s["planned"] += 1
        timed = []
        t = day_start
        for subj, kind in today:
            if t is not None:
                end = t + session
                timed.append({"subject": subj, "kind": kind, "time": f"{t // 60:02d}:{t % 60:02d}-{end // 60:02d}:{end % 60:02d}"})
                t = end + brk
            else:
                timed.append({"subject": subj, "kind": kind})
        timetable.append({"date": day.isoformat(), "dow": DAYS[day.weekday()], "exams": exam_days.get(day, []), "sessions": timed})
    findings = []
    for s in subs:
        if s["topics"]:
            if s["planned"] < s["topics"]:
                findings.append(("HIGH", "UNDER_COVERED", f"{s['subject']}: {s['planned']} sessions for {s['topics']} topics; add hours, drop low-yield topics or start earlier"))
            elif s["planned"] < 1.5 * s["topics"]:
                findings.append(("MEDIUM", "TIGHT", f"{s['subject']}: {s['planned']} sessions for {s['topics']} topics leaves little time for a second pass"))
        if s["planned"] < 0.6 * s["target"]:
            findings.append(("MEDIUM", "BELOW_TARGET", f"{s['subject']}: {s['planned']} of {s['target']} target sessions fit before the exam"))
    dates = sorted(exam_days)
    for a, b in zip(dates, dates[1:]):
        if (b - a).days <= 1:
            findings.append(("MEDIUM", "BACK_TO_BACK", f"exams on {a} ({', '.join(exam_days[a])}) and {b} ({', '.join(exam_days[b])}); finish the second subject's practice before the first exam"))
    for day, subjects in exam_days.items():
        if len(subjects) > 1:
            findings.append(("MEDIUM", "SAME_DAY", f"{len(subjects)} exams on {day}: {', '.join(subjects)}"))
    if rest_day is None and len(days) > 10 and not off:
        findings.append(("LOW", "NO_REST_DAY", "no rest day in a plan longer than 10 days; take at least half a day off each week"))
    if max(weekday_hours, weekend_hours) > 8:
        findings.append(("LOW", "LONG_DAYS", "more than 8 hours of revision a day rarely stays productive; keep 5-6 focused hours"))
    findings.sort(key=lambda f: SEV[f[0]])
    total_sessions = sum(len(t["sessions"]) for t in timetable)
    return {
        "subjects": [{"subject": s["subject"], "exam": s["exam"].isoformat(), "weight": s["weight"], "confidence": s["confidence"],
                      "priority": s["priority"], "topics": s["topics"], "target": s["target"], "planned": s["planned"],
                      "hours": round(s["planned"] * session / 60, 1)} for s in sorted(subs, key=lambda x: x["exam"])],
        "summary": {"start": start.isoformat(), "last_exam": last.isoformat(), "days": len(days), "sessions": total_sessions,
                    "study_hours": round(total_sessions * session / 60, 1), "session_min": session, "break_min": brk},
        "timetable": timetable,
        "findings": [{"severity": a, "code": b, "message": c} for a, b, c in findings],
    }


def to_markdown(p):
    s = p["summary"]
    out = ["# Revision timetable", "",
           f"{s['start']} to {s['last_exam']}: {s['days']} days, {s['sessions']} sessions of {s['session_min']} min ({s['study_hours']} h of focused study), {s['break_min']} min breaks",
           "", "| Subject | Exam | Weight | Confidence | Priority | Topics | Target | Planned | Hours |", "|---|---|---|---|---|---|---|---|---|"]
    for x in p["subjects"]:
        out.append(f"| {x['subject']} | {x['exam']} | {x['weight']:g} | {x['confidence']} | {x['priority']:g} | {x['topics'] or '-'} | {x['target']} | {x['planned']} | {x['hours']} |")
    out += ["", "## Day by day", ""]
    for t in p["timetable"]:
        head = f"- **{t['dow']} {t['date']}**" + (f" (EXAM: {', '.join(t['exams'])})" if t["exams"] else "")
        if not t["sessions"]:
            out.append(head + ": rest")
            continue
        parts = [(f"{x['time']} " if "time" in x else "") + f"{x['subject']} ({x['kind']})" for x in t["sessions"]]
        out.append(head + ": " + "; ".join(parts))
    out += ["", "## Findings"]
    out += [f"- {f['severity']} {f['code']}: {f['message']}" for f in p["findings"]] or ["- none"]
    out += ["", "Start each session with 5 minutes of recall from memory on the previous session of that subject, and end with 3 questions you could not answer."]
    return "\n".join(out)


def self_test():
    res = []

    def check(name, cond):
        res.append(cond)
        print(("PASS " if cond else "FAIL ") + name)

    D = dt.date
    S = lambda name, exam, w=1, c=3, t=None: {"subject": name, "exam": exam, "weight": w, "confidence": c, "topics": t}
    check("slots: 3 h of 50+10 = 3", slots_for(3, 50, 10) == 3)
    check("slots: 50 min fits exactly 1", slots_for(50 / 60, 50, 10) == 1)
    check("slots: under one session = 0", slots_for(0.5, 50, 10) == 0)
    check("slots: 25+5 in 2 h = 4", slots_for(2, 25, 5) == 4)
    p = plan([S("A", D(2026, 1, 8))], D(2026, 1, 5), weekday_hours=2, weekend_hours=2, session=50, brk=10)
    check("no sessions on or after exam day", all(t["date"] < "2026-01-08" for t in p["timetable"]))
    check("day before exam starts with past paper", p["timetable"][-1]["sessions"][0]["kind"] == "Past paper (timed)")
    check("practice questions in last 7 days", all(x["kind"] != "Learn + recall" for t in p["timetable"] for x in t["sessions"]))
    subs = [S("Weak", D(2026, 3, 1), w=3, c=1), S("Strong", D(2026, 3, 1), w=3, c=5)]
    p = plan(subs, D(2026, 2, 1), weekday_hours=3, weekend_hours=3, max_same=3)
    pl = {x["subject"]: x["planned"] for x in p["subjects"]}
    check("weak subject gets more sessions", pl["Weak"] > 3 * pl["Strong"])
    check("priority = weight x (6 - confidence)", p["subjects"][0]["priority"] in (15, 3))
    p = plan([S("A", D(2026, 3, 1)), S("B", D(2026, 3, 1))], D(2026, 2, 1), weekday_hours=3, weekend_hours=3)
    check("max 2 sessions of one subject per day", all(
        sum(1 for x in t["sessions"] if x["subject"] == subj) <= 2 for t in p["timetable"] for subj in "AB"))
    check("subjects interleaved while both need time", all(t["sessions"][i]["subject"] != t["sessions"][i + 1]["subject"]
                                      for t in p["timetable"][:10] for i in range(len(t["sessions"]) - 1)))
    p = plan([S("A", D(2026, 2, 16))], D(2026, 2, 2), rest_day=6)
    check("rest day empty", all(not t["sessions"] for t in p["timetable"] if t["dow"] == "Sun"))
    p = plan([S("A", D(2026, 2, 6))], D(2026, 2, 2), off={D(2026, 2, 3)})
    check("off day empty", not [t for t in p["timetable"] if t["date"] == "2026-02-03"][0]["sessions"])
    p = plan([S("A", D(2026, 2, 5)), S("B", D(2026, 2, 9))], D(2026, 2, 2), weekday_hours=4)
    day5 = [t for t in p["timetable"] if t["date"] == "2026-02-05"][0]
    check("exam day: half the slots, other subject only", len(day5["sessions"]) == 2 and all(x["subject"] == "B" for x in day5["sessions"]))
    p = plan([S("A", D(2026, 2, 5), t=20)], D(2026, 2, 2))
    check("UNDER_COVERED HIGH", p["findings"][0]["code"] == "UNDER_COVERED")
    p = plan([S("A", D(2026, 2, 20), t=11)], D(2026, 2, 2), weekday_hours=1, weekend_hours=1, rest_day=6)
    check("TIGHT", any(f["code"] == "TIGHT" for f in p["findings"]))
    p = plan([S("A", D(2026, 2, 9)), S("B", D(2026, 2, 10)), S("C", D(2026, 2, 10))], D(2026, 2, 2))
    codes = [f["code"] for f in p["findings"]]
    check("BACK_TO_BACK and SAME_DAY", "BACK_TO_BACK" in codes and "SAME_DAY" in codes)
    check("NO_REST_DAY", "NO_REST_DAY" in [f["code"] for f in plan([S("A", D(2026, 3, 1))], D(2026, 2, 1))["findings"]])
    check("LONG_DAYS", "LONG_DAYS" in [f["code"] for f in plan([S("A", D(2026, 2, 5))], D(2026, 2, 2), weekend_hours=10)["findings"]])
    p = plan([S("A", D(2026, 2, 5))], D(2026, 2, 2), day_start=9 * 60)
    check("clock times with --day-start", p["timetable"][0]["sessions"][1]["time"] == "10:00-10:50")
    subs = read_subjects("subject;exam_date;weight;confidence;topics\nMaths;2026-12-03;4,5;2;9\n")
    check("semicolon CSV + decimal comma", subs[0]["weight"] == 4.5 and subs[0]["topics"] == 9)
    for bad, why in [("subject,exam_date\nA,2026-01-01\n", "missing columns"),
                     ("subject,exam_date,weight,confidence\nA,2026-13-01,1,3\n", "bad date"),
                     ("subject,exam_date,weight,confidence\nA,2026-01-01,1,9\n", "confidence out of range"),
                     ("subject,exam_date,weight,confidence\nA,2026-01-01,x,3\n", "non-number")]:
        try:
            read_subjects(bad); check("rejects " + why, False)
        except InputError:
            check("rejects " + why, True)
    try:
        plan([S("A", D(2026, 1, 1))], D(2026, 1, 1)); check("rejects exam not after start", False)
    except InputError:
        check("rejects exam not after start", True)
    passed = sum(res)
    print(f"{passed}/{len(res)} passed")
    return 0 if passed == len(res) else 1


def main():
    ap = argparse.ArgumentParser(description="Exam revision timetable planner")
    ap.add_argument("csv", nargs="?", help="subjects CSV")
    ap.add_argument("--start", help="first revision day YYYY-MM-DD (default today)")
    ap.add_argument("--weekday-hours", type=float, default=3.0)
    ap.add_argument("--weekend-hours", type=float, default=5.0)
    ap.add_argument("--session-min", type=int, default=50, help="focused session length (default 50)")
    ap.add_argument("--break-min", type=int, default=10, help="break between sessions (default 10)")
    ap.add_argument("--rest-day", choices=DAYS, help="weekly day off")
    ap.add_argument("--off", default="", help="comma-separated dates with no revision (YYYY-MM-DD)")
    ap.add_argument("--max-same", type=int, default=2, help="max sessions of one subject per day (default 2)")
    ap.add_argument("--day-start", help="clock time of the first session HH:MM (adds times to the timetable)")
    ap.add_argument("--json", action="store_true")
    ap.add_argument("--self-test", action="store_true")
    a = ap.parse_args()
    if a.self_test:
        return self_test()
    if not a.csv:
        ap.error("give a CSV, or --self-test")
    try:
        with open(a.csv, encoding="utf-8-sig") as fh:
            subs = read_subjects(fh.read())
        start = parse_date(a.start, "--start") if a.start else dt.date.today()
        off = {parse_date(x, "--off") for x in a.off.split(",") if x.strip()}
        ds = None
        if a.day_start:
            try:
                h, m = map(int, a.day_start.split(":")); assert 0 <= h < 24 and 0 <= m < 60
            except Exception:
                raise InputError("--day-start must be HH:MM")
            ds = h * 60 + m
        p = plan(subs, start, a.weekday_hours, a.weekend_hours, a.session_min, a.break_min,
                 DAYS.index(a.rest_day) if a.rest_day else None, off, a.max_same, ds)
    except (OSError, InputError) as e:
        print(f"error: {e}", file=sys.stderr)
        return 2
    print(json.dumps(p, indent=2) if a.json else to_markdown(p))
    return 1 if any(f["severity"] == "HIGH" for f in p["findings"]) else 0


if __name__ == "__main__":
    sys.exit(main())
PythonStudentsEducation+2
F@f
0
Chuyên gia đánh giá nội dung Toán học
Văn bản

Tôi là một chuyên gia nội dung (SME) về môn Toán, đặc biệt là nội dung chương trình Ấn Độ. Tôi đang có các tệp HTML do các lập trình viên/nhà thiết kế tạo ra. Tôi muốn đánh giá chúng dưới cả góc độ sư phạm lẫn góc độ thiết kế. Ngoài ra, giả sử nội dung nào đó dành cho lớp 8 thì ngay cả học sinh lớp 7 cũng có thể hiểu được, tệp HTML đó cần phải mượt mà và hấp dẫn đến mức như vậy.

Tôi là một chuyên gia nội dung (SME) về môn Toán, đặc biệt là nội dung chương trình Ấn Độ. Tôi đang có các tệp HTML do các lập trình viên/nhà thiết kế tạo ra. Tôi muốn đánh giá chúng dưới cả góc độ sư phạm lẫn góc độ thiết kế. Ngoài ra, giả sử nội dung nào đó dành cho lớp 8 thì ngay cả học sinh lớp 7 cũng có thể hiểu được, tệp HTML đó cần phải mượt mà và hấp dẫn đến mức như vậy.
DesignMathReview+1
S@singhrajesh9652979
0