feat: YAML content importer + phys/ct-2024 collection (proof)
content/phys/ct-2024.yaml — 15 questions from ЦЭ,ЦТ 2024 across 6 topics (kinem, mol, emf, electro, magnet, optics) as proof of format. backend/scripts/import-content.js — unified importer: - Validates schema (subject, year, options, exactly-1-correct) - Aliases (kinem, mol, ...) resolve to Russian topic names via get-or-create - Deduplicates by first 80 chars of text (matches legacy seed_*.js behavior) - Runs in a single transaction, idempotent re-runs On fresh DB: 13 added (2 dedup collisions — same 80-char prefix, expected). On prod DB: 0 added (all already exist from legacy seeds). Second run on either: 0 added (dedup works). Legacy seed_phys_ct2024.js kept as backup — see content/README.md for migration guide. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Generated
+19
@@ -13,6 +13,7 @@
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.18.3",
|
||||
"js-yaml": "^4.1.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"multer": "^2.1.1",
|
||||
"sharp": "^0.34.5",
|
||||
@@ -530,6 +531,12 @@
|
||||
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
@@ -1255,6 +1262,18 @@
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"seed": "node src/db/seed.js",
|
||||
"seed:permissions": "node src/db/seed-permissions.js",
|
||||
"lint:routes": "node scripts/check-route-auth.js",
|
||||
"import:content": "node scripts/import-content.js",
|
||||
"test": "node --test tests/*.test.js"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -18,6 +19,7 @@
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.18.3",
|
||||
"js-yaml": "^4.1.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"multer": "^2.1.1",
|
||||
"sharp": "^0.34.5",
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* import-content.js — imports question collections from YAML manifests.
|
||||
*
|
||||
* Usage:
|
||||
* npm run import:content -- ../content/phys/ct-2024.yaml
|
||||
*
|
||||
* YAML format: content/README.md
|
||||
*
|
||||
* Topic aliases (subject=phys):
|
||||
* kinem=29, dynam=30, cons=31, mol=32, thermo=33, electro=34,
|
||||
* dc=35, magnet=36, emf=37, optics=38, quantum=39, waves=40
|
||||
*
|
||||
* For subjects without predefined aliases, or for additional topics,
|
||||
* add entries to SUBJECT_TOPIC_MAP below, or use full topic name strings
|
||||
* as topic keys (they will be looked up / created automatically).
|
||||
*/
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const yaml = require('js-yaml');
|
||||
const db = require('../src/db/db');
|
||||
|
||||
/* ── Subject → topic alias → topic name (for get-or-create lookup) ────── */
|
||||
const SUBJECT_ID_MAP = { bio: 1, chem: 2, math: 3, phys: 4 };
|
||||
|
||||
const SUBJECT_TOPIC_NAMES = {
|
||||
phys: {
|
||||
kinem: 'Кинематика',
|
||||
dynam: 'Динамика',
|
||||
cons: 'Законы сохранения',
|
||||
mol: 'Молекулярная физика',
|
||||
thermo: 'Термодинамика',
|
||||
electro: 'Электростатика',
|
||||
dc: 'Постоянный ток',
|
||||
magnet: 'Магнетизм',
|
||||
emf: 'Электромагнитная индукция',
|
||||
optics: 'Оптика',
|
||||
quantum: 'Квантовая и ядерная физика',
|
||||
waves: 'Колебания и волны',
|
||||
},
|
||||
// Add math/bio/chem topic name maps here as collections are migrated
|
||||
};
|
||||
|
||||
/* ── Look up or create topic by name (alias or full name) ─────────────── */
|
||||
function resolveTopicId(subjectId, key) {
|
||||
const subjectSlug = Object.keys(SUBJECT_ID_MAP).find(s => SUBJECT_ID_MAP[s] === subjectId);
|
||||
const aliasMap = SUBJECT_TOPIC_NAMES[subjectSlug] || {};
|
||||
|
||||
// Resolve alias → full topic name (or use key as-is if it's already a name)
|
||||
const topicName = aliasMap[key] || key;
|
||||
|
||||
const existing = db.prepare('SELECT id FROM topics WHERE subject_id=? AND LOWER(name)=LOWER(?)').get(subjectId, topicName);
|
||||
if (existing) return existing.id;
|
||||
|
||||
const { lastInsertRowid } = db.prepare('INSERT INTO topics (subject_id, name) VALUES (?,?)').run(subjectId, topicName);
|
||||
console.log(`[import] Created new topic: "${topicName}" (id=${lastInsertRowid})`);
|
||||
return Number(lastInsertRowid);
|
||||
}
|
||||
|
||||
/* ── Validation ──────────────────────────────────────────────────────── */
|
||||
function validate(doc, file) {
|
||||
const errors = [];
|
||||
|
||||
if (!doc || typeof doc !== 'object') { errors.push('document must be an object'); }
|
||||
if (!doc?.meta?.subject) errors.push('meta.subject required');
|
||||
if (!doc?.meta?.year) errors.push('meta.year required');
|
||||
if (!SUBJECT_ID_MAP[doc?.meta?.subject]) errors.push(`unknown subject "${doc?.meta?.subject}" (valid: ${Object.keys(SUBJECT_ID_MAP).join(', ')})`);
|
||||
if (!doc?.topics || typeof doc.topics !== 'object') errors.push('topics object required');
|
||||
|
||||
if (doc?.topics) {
|
||||
for (const [topicKey, items] of Object.entries(doc.topics)) {
|
||||
if (!Array.isArray(items)) { errors.push(`topics.${topicKey} must be array`); continue; }
|
||||
items.forEach((q, i) => {
|
||||
const loc = `topics.${topicKey}[${i}]`;
|
||||
if (!q.text || typeof q.text !== 'string') errors.push(`${loc}: text required (string)`);
|
||||
if (!Array.isArray(q.options)) errors.push(`${loc}: options array required`);
|
||||
else {
|
||||
const correctCount = q.options.filter(o => o.correct).length;
|
||||
if (correctCount !== 1) errors.push(`${loc}: exactly 1 correct option required (got ${correctCount})`);
|
||||
q.options.forEach((o, oi) => {
|
||||
if (!o.text) errors.push(`${loc}.options[${oi}]: text required`);
|
||||
});
|
||||
}
|
||||
if (q.difficulty !== undefined && ![1, 2, 3].includes(Number(q.difficulty)))
|
||||
errors.push(`${loc}: difficulty must be 1, 2, or 3`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
console.error(`\n[import] FAIL: validation errors in ${path.basename(file)}:`);
|
||||
errors.forEach(e => console.error(` - ${e}`));
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Import ──────────────────────────────────────────────────────────── */
|
||||
function importFile(file) {
|
||||
const raw = fs.readFileSync(file, 'utf8');
|
||||
const doc = yaml.load(raw);
|
||||
validate(doc, file);
|
||||
|
||||
const subjectId = SUBJECT_ID_MAP[doc.meta.subject];
|
||||
const year = doc.meta.year;
|
||||
|
||||
// Dedup: skip questions whose first 80 chars already exist for this subject
|
||||
const existingTexts = new Set(
|
||||
db.prepare('SELECT text FROM questions WHERE subject_id=?').all(subjectId)
|
||||
.map(q => q.text.slice(0, 80).trim())
|
||||
);
|
||||
|
||||
const insertQ = db.prepare(
|
||||
'INSERT INTO questions (subject_id, topic_id, text, type, difficulty, year, explanation) VALUES (?,?,?,?,?,?,?)'
|
||||
);
|
||||
const insertO = db.prepare(
|
||||
'INSERT INTO options (question_id, text, is_correct, order_index) VALUES (?,?,?,?)'
|
||||
);
|
||||
|
||||
let added = 0, skipped = 0;
|
||||
|
||||
db.transaction(() => {
|
||||
for (const [topicKey, items] of Object.entries(doc.topics)) {
|
||||
const topicId = resolveTopicId(subjectId, topicKey);
|
||||
|
||||
for (const q of items) {
|
||||
const text = q.text.trim();
|
||||
const key = text.slice(0, 80).trim();
|
||||
|
||||
if (existingTexts.has(key)) { skipped++; continue; }
|
||||
existingTexts.add(key);
|
||||
|
||||
const { lastInsertRowid } = insertQ.run(
|
||||
subjectId,
|
||||
topicId,
|
||||
text,
|
||||
q.type || 'single',
|
||||
Number(q.difficulty) || 1,
|
||||
year,
|
||||
q.explanation || null
|
||||
);
|
||||
|
||||
const qid = Number(lastInsertRowid);
|
||||
q.options.forEach((o, i) => insertO.run(qid, o.text, o.correct ? 1 : 0, i));
|
||||
added++;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
const source = doc.meta.source ? ` (${doc.meta.source})` : '';
|
||||
console.log(`[import] ${path.basename(file)}${source} — added ${added}, skipped ${skipped} duplicates`);
|
||||
return { added, skipped };
|
||||
}
|
||||
|
||||
/* ── Entry point ─────────────────────────────────────────────────────── */
|
||||
const file = process.argv[2];
|
||||
if (!file) {
|
||||
console.error('Usage: node import-content.js <path/to/collection.yaml>');
|
||||
console.error(' npm run import:content -- ../content/phys/ct-2024.yaml');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const resolved = path.resolve(file);
|
||||
if (!fs.existsSync(resolved)) {
|
||||
console.error(`[import] File not found: ${resolved}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
importFile(resolved);
|
||||
@@ -0,0 +1,80 @@
|
||||
# Content as data
|
||||
|
||||
Question collections live here as YAML, imported via a single CLI.
|
||||
This replaces the ad-hoc `backend/scripts/seed_phys_ct2024.js` pattern.
|
||||
|
||||
## Import command
|
||||
|
||||
```sh
|
||||
cd backend
|
||||
npm run import:content -- ../content/phys/ct-2024.yaml
|
||||
```
|
||||
|
||||
## File format
|
||||
|
||||
```yaml
|
||||
meta:
|
||||
subject: phys # phys | math | bio | chem
|
||||
year: 2024 # exam year (integer)
|
||||
source: "ЦЭ,ЦТ 2024" # optional label shown in import log
|
||||
|
||||
topics:
|
||||
kinem: # topic alias (see aliases below)
|
||||
- text: |
|
||||
Question text (multi-line supported, LaTeX with \( \) works)
|
||||
difficulty: 1 # 1=easy, 2=medium, 3=hard (default: 1)
|
||||
explanation: "Solution explanation" # optional
|
||||
options:
|
||||
- { text: "Answer A", correct: true } # exactly ONE correct
|
||||
- { text: "Answer B" }
|
||||
- { text: "Answer C" }
|
||||
|
||||
"Full topic name": # or use full Russian name — will be found or created
|
||||
- text: "..."
|
||||
options: [...]
|
||||
```
|
||||
|
||||
## Topic aliases (subject=phys)
|
||||
|
||||
| Alias | Topic name |
|
||||
|----------|---------------------------------|
|
||||
| kinem | Кинематика |
|
||||
| dynam | Динамика |
|
||||
| cons | Законы сохранения |
|
||||
| mol | Молекулярная физика |
|
||||
| thermo | Термодинамика |
|
||||
| electro | Электростатика |
|
||||
| dc | Постоянный ток |
|
||||
| magnet | Магнетизм |
|
||||
| emf | Электромагнитная индукция |
|
||||
| optics | Оптика |
|
||||
| quantum | Квантовая и ядерная физика |
|
||||
| waves | Колебания и волны |
|
||||
|
||||
For other topic names, use the full Russian name as the key — the importer
|
||||
looks it up in the database (case-insensitive) or creates a new topic.
|
||||
|
||||
## Dedup logic
|
||||
|
||||
Questions are skipped if the first 80 characters of their text already
|
||||
exist in the database for the same subject. This matches the legacy
|
||||
`seed_phys_*.js` behavior, ensuring idempotent re-runs.
|
||||
|
||||
## Migrating a legacy seed_*.js
|
||||
|
||||
1. Copy the file structure from `content/phys/ct-2024.yaml`
|
||||
2. Convert each `q(T.kinem, text, opts, diff, year, expl)` call to YAML:
|
||||
- `T.kinem` → `topics: kinem:`
|
||||
- `text` → `text: |` (use literal block for multi-line)
|
||||
- `opts: [{t: "...", c: true}, ...]` → `options: [{text: "...", correct: true}, ...]`
|
||||
- `diff` → `difficulty:`
|
||||
- `expl` → `explanation:`
|
||||
3. Run `npm run import:content -- ../content/<subject>/<file>.yaml`
|
||||
4. Verify output shows expected `added` count
|
||||
5. Keep the legacy `seed_*.js` file as backup until verified
|
||||
|
||||
## Collections
|
||||
|
||||
| File | Subject | Year | Source | Questions |
|
||||
|------|---------|------|--------|-----------|
|
||||
| phys/ct-2024.yaml | Физика | 2024 | ЦЭ,ЦТ 2024 | 13 (proof subset) |
|
||||
@@ -0,0 +1,211 @@
|
||||
meta:
|
||||
subject: phys
|
||||
year: 2024
|
||||
source: "ЦЭ,ЦТ 2024"
|
||||
|
||||
# Topic keys map to predefined topic IDs for subject=phys:
|
||||
# kinem=29, dynam=30, cons=31, mol=32, thermo=33, electro=34,
|
||||
# dc=35, magnet=36, emf=37, optics=38, quantum=39, waves=40
|
||||
|
||||
topics:
|
||||
kinem:
|
||||
- text: |
|
||||
Из перечисленных физических величин ВЕКТОРНЫМИ являются:
|
||||
1) сила; 2) масса; 3) плотность; 4) объём; 5) ускорение.
|
||||
(Укажите ВСЕ номера верных ответов.)
|
||||
difficulty: 1
|
||||
explanation: "Сила и ускорение — векторные величины; масса, плотность, объём — скалярные."
|
||||
options:
|
||||
- { text: "1 и 5", correct: true }
|
||||
- { text: "1 и 3" }
|
||||
- { text: "2 и 4" }
|
||||
- { text: "3 и 5" }
|
||||
- { text: "1, 3 и 5" }
|
||||
|
||||
- text: |
|
||||
Из перечисленных физических величин ВЕКТОРНЫМИ являются:
|
||||
1) площадь; 2) ускорение; 3) импульс; 4) масса; 5) время.
|
||||
(Укажите ВСЕ номера верных ответов.)
|
||||
difficulty: 1
|
||||
explanation: "Ускорение и импульс — векторные величины; площадь, масса, время — скалярные."
|
||||
options:
|
||||
- { text: "2 и 3", correct: true }
|
||||
- { text: "1 и 4" }
|
||||
- { text: "3 и 5" }
|
||||
- { text: "1 и 2" }
|
||||
- { text: "4 и 5" }
|
||||
|
||||
- text: |
|
||||
Из перечисленных физических величин ВЕКТОРНЫМИ являются:
|
||||
1) сила; 2) плотность; 3) перемещение; 4) время; 5) объём.
|
||||
(Укажите ВСЕ номера верных ответов.)
|
||||
difficulty: 1
|
||||
explanation: "Сила и перемещение — векторные; плотность, время, объём — скалярные."
|
||||
options:
|
||||
- { text: "1 и 3", correct: true }
|
||||
- { text: "2 и 5" }
|
||||
- { text: "3 и 4" }
|
||||
- { text: "1 и 4" }
|
||||
- { text: "2 и 4" }
|
||||
|
||||
- text: |
|
||||
Из перечисленных физических величин ВЕКТОРНЫМИ являются:
|
||||
1) импульс; 2) скорость; 3) масса; 4) плотность; 5) работа.
|
||||
(Укажите ВСЕ номера верных ответов.)
|
||||
difficulty: 1
|
||||
explanation: "Импульс и скорость — векторные; масса, плотность, работа — скалярные."
|
||||
options:
|
||||
- { text: "1 и 2", correct: true }
|
||||
- { text: "3 и 4" }
|
||||
- { text: "2 и 5" }
|
||||
- { text: "1 и 4" }
|
||||
- { text: "3 и 5" }
|
||||
|
||||
mol:
|
||||
- text: |
|
||||
Если \(m_0\) — масса молекулы, \(n\) — концентрация молекул идеального газа, а \(\langle v^2 \rangle\) — среднее значение квадрата скорости теплового движения молекул, то давление \(p\) газа равно:
|
||||
1) \(p=\dfrac{5}{2}m_0 n\langle v^2\rangle\);
|
||||
2) \(p=\dfrac{3}{2}m_0 n\langle v^2\rangle\);
|
||||
3) \(p=\dfrac{1}{3}m_0 n\langle v^2\rangle\);
|
||||
4) \(p=m_0 n\langle v^2\rangle\);
|
||||
5) \(p=\dfrac{2}{3}m_0 n\langle v^2\rangle\).
|
||||
difficulty: 2
|
||||
explanation: "Основное уравнение МКТ: \\(p=\\frac{1}{3}m_0 n\\langle v^2\\rangle\\)."
|
||||
options:
|
||||
- { text: "3", correct: true }
|
||||
- { text: "1" }
|
||||
- { text: "2" }
|
||||
- { text: "4" }
|
||||
- { text: "5" }
|
||||
|
||||
- text: |
|
||||
Если \(T\) — абсолютная температура идеального газа, \(k\) — постоянная Больцмана, то среднюю кинетическую энергию \(\langle E_\text{к}\rangle\) поступательного движения частиц газа можно вычислить по формуле:
|
||||
1) \(\langle E_\text{к}\rangle=kT\);
|
||||
2) \(\langle E_\text{к}\rangle=\dfrac{1}{2}kT\);
|
||||
3) \(\langle E_\text{к}\rangle=\dfrac{3}{2}kT\);
|
||||
4) \(\langle E_\text{к}\rangle=2kT\);
|
||||
5) \(\langle E_\text{к}\rangle=\dfrac{2}{3}kT\).
|
||||
difficulty: 1
|
||||
explanation: "Средняя кинетическая энергия поступательного движения: \\(\\langle E_\\text{к}\\rangle=\\frac{3}{2}kT\\)."
|
||||
options:
|
||||
- { text: "3", correct: true }
|
||||
- { text: "1" }
|
||||
- { text: "2" }
|
||||
- { text: "4" }
|
||||
- { text: "5" }
|
||||
|
||||
- text: |
|
||||
Если \(T\) — абсолютная температура идеального газа, \(k\) — постоянная Больцмана, \(n\) — концентрация частиц газа, то давление \(p\) газа можно вычислить по формуле:
|
||||
1) \(p=nkT\);
|
||||
2) \(p=\dfrac{1}{2}nkT\);
|
||||
3) \(p=\dfrac{3}{2}nkT\);
|
||||
4) \(p=\dfrac{2}{3}nkT\);
|
||||
5) \(p=2nkT\).
|
||||
difficulty: 1
|
||||
explanation: "Уравнение состояния идеального газа в форме МКТ: \\(p=nkT\\)."
|
||||
options:
|
||||
- { text: "1", correct: true }
|
||||
- { text: "2" }
|
||||
- { text: "3" }
|
||||
- { text: "4" }
|
||||
- { text: "5" }
|
||||
|
||||
emf:
|
||||
- text: |
|
||||
Физической величиной, измеряемой в веберах (Вб), является:
|
||||
1) сила Ампера; 2) индуктивность; 3) электрическое сопротивление; 4) магнитный поток; 5) электрическое напряжение.
|
||||
difficulty: 1
|
||||
explanation: "Вебер (Вб) — единица магнитного потока \\(\\Phi\\)."
|
||||
options:
|
||||
- { text: "4", correct: true }
|
||||
- { text: "1" }
|
||||
- { text: "2" }
|
||||
- { text: "3" }
|
||||
- { text: "5" }
|
||||
|
||||
- text: |
|
||||
Физической величиной, измеряемой в вольтах (В), является:
|
||||
1) сила Ампера; 2) сила тока; 3) ЭДС электромагнитной индукции; 4) индуктивность; 5) электрическое сопротивление.
|
||||
difficulty: 1
|
||||
explanation: "ЭДС измеряется в вольтах (В)."
|
||||
options:
|
||||
- { text: "3", correct: true }
|
||||
- { text: "1" }
|
||||
- { text: "2" }
|
||||
- { text: "4" }
|
||||
- { text: "5" }
|
||||
|
||||
- text: |
|
||||
Физической величиной, измеряемой в генри (Гн), является:
|
||||
1) электрическое сопротивление; 2) сила Ампера; 3) электрическое напряжение; 4) сила тока; 5) индуктивность.
|
||||
difficulty: 1
|
||||
explanation: "Генри (Гн) — единица индуктивности \\(L\\)."
|
||||
options:
|
||||
- { text: "5", correct: true }
|
||||
- { text: "1" }
|
||||
- { text: "2" }
|
||||
- { text: "3" }
|
||||
- { text: "4" }
|
||||
|
||||
electro:
|
||||
- text: |
|
||||
Физической величиной, измеряемой в вольтах (В), является:
|
||||
1) сила Ампера; 2) сила тока; 3) электрическое сопротивление; 4) электрический заряд; 5) потенциал электростатического поля.
|
||||
difficulty: 1
|
||||
explanation: "Вольт (В) — единица электрического потенциала и напряжения."
|
||||
options:
|
||||
- { text: "5", correct: true }
|
||||
- { text: "1" }
|
||||
- { text: "2" }
|
||||
- { text: "3" }
|
||||
- { text: "4" }
|
||||
|
||||
magnet:
|
||||
- text: |
|
||||
Физической величиной, измеряемой в теслах (Тл), является:
|
||||
1) сила Ампера; 2) индуктивность; 3) индукция магнитного поля; 4) электрический заряд; 5) сила тока.
|
||||
difficulty: 1
|
||||
explanation: "Тесла (Тл) — единица индукции магнитного поля \\(B\\)."
|
||||
options:
|
||||
- { text: "3", correct: true }
|
||||
- { text: "1" }
|
||||
- { text: "2" }
|
||||
- { text: "4" }
|
||||
- { text: "5" }
|
||||
|
||||
optics:
|
||||
- text: |
|
||||
Если в наборе дифракционных решёток имеются решётки с числом штрихов 500; 750; 1000; 1250; 2000 на длине \(l=1\) см, то наименьший период \(d\) имеет решётка с числом штрихов:
|
||||
1) 500; 2) 750; 3) 1000; 4) 1250; 5) 2000.
|
||||
difficulty: 1
|
||||
explanation: "\\(d=l/N\\). Наименьший \\(d\\) при наибольшем числе штрихов \\(N=2000\\)."
|
||||
options:
|
||||
- { text: "5", correct: true }
|
||||
- { text: "4" }
|
||||
- { text: "3" }
|
||||
- { text: "2" }
|
||||
- { text: "1" }
|
||||
|
||||
- text: |
|
||||
Если в наборе дифракционных решёток имеются решётки с числом штрихов 50; 75; 100; 150; 200 на длине \(l=1\) мм, то наибольший период \(d\) имеет решётка с числом штрихов:
|
||||
1) 50; 2) 75; 3) 100; 4) 150; 5) 200.
|
||||
difficulty: 1
|
||||
explanation: "\\(d=l/N\\). Наибольший \\(d\\) при наименьшем \\(N=50\\): \\(d=1/50=0{,}02\\) мм."
|
||||
options:
|
||||
- { text: "1", correct: true }
|
||||
- { text: "2" }
|
||||
- { text: "3" }
|
||||
- { text: "4" }
|
||||
- { text: "5" }
|
||||
|
||||
- text: |
|
||||
Если предмет находится перед плоским зеркалом на расстоянии 10 см от него, то расстояние между предметом и его изображением в зеркале равно:
|
||||
1) 5 см; 2) 10 см; 3) 20 см; 4) 30 см; 5) 40 см.
|
||||
difficulty: 1
|
||||
explanation: "Изображение в плоском зеркале симметрично предмету — на таком же расстоянии за зеркалом. Расстояние предмет–изображение = 2×10 = 20 см."
|
||||
options:
|
||||
- { text: "3", correct: true }
|
||||
- { text: "1" }
|
||||
- { text: "2" }
|
||||
- { text: "4" }
|
||||
- { text: "5" }
|
||||
Reference in New Issue
Block a user