Начни здесь

Фабрика курсов: package-tutorial-factory

Курс о пакете, которым сделан этот курс. За одиннадцать секций ты пройдёшь весь конвейер фабрики — от разбора пакета до сайта, который проверяют, проходя его кликами, — и соберёшь собственный курс по своему пакету.

Знакомься: Мира

Мира — участница harness-мастерской. Она уже прошла курсы по dz и по конвейеру фич, а теперь столкнулась с новой бедой: её пакет читают по диагонали и забывают. В этом курсе она превращает свой README в настоящий курс — а ты идёшь рядом и принимаешь те же решения.

Содержание курса

1. Зачем нужна фабрика курсов

Какую проблему решает пакет и почему README недостаточно

Ключевая мысль: фабрика курсов

Привет! Ты держишь в руках инструмент, которым сделан этот самый курс. Да, именно так: страницу, которую ты читаешь, собрал пакет @dzhechkov/skills-tutorial-factory — та самая фабрика курсов, про которую он и рассказывает.

Знакомься: Мира. Она уже прошла курс по dz и курс по конвейеру фич, так что терминал её не пугает. Но сегодня у неё новая беда. Мира написала хороший пакет, приложила README на двадцать экранов — и через неделю выяснила, что коллеги пролистали его один раз и забыли. Документацию читают по диагонали. Курс — проходят.

Что делает фабрика курсов:
- сама разбирает пакет — README, файлы навыков, экспорты, тесты — и составляет список тем;
- пишет курс по методу Head First — с живым персонажем, упражнениями и наградами;
- проверяет результат машиной, а не на глаз: сначала структурный гейт, потом запуск готового сайта.

Главное отличие от «попроси модель написать курс»: метод здесь не зашит в код. Он вынесен в отдельный файл — метод-базу, и каждая секция обязана сослаться на конкретный приём оттуда. Хочешь изменить метод — правь файл, а не программу.

Исходники и публичное зеркало: github.com/djd1m/dz-harness.

Компромиссы: сильная сторона — курс выходит воспроизводимым: те же входные данные дают тот же результат, а проверки ловят пустышки. Слабая сторона — фабрика бесполезна там, где учить нечему: если у пакета нет ни README, ни навыков, она честно откажется, а не выдаст курс из одной страницы.

💬 Просто попроси.
- «Сделай курс по этому пакету» → ассистент вызовет навык package-tutorial-factory и начнёт с разбора твоего пакета.
- «Чем курс лучше README?» → ассистент покажет раздел When to use it и назовёт случаи, где фабрика не нужна.

2. Установка навыка package-tutorial-factory

Как поставить фабрику в проект и чем проверить, что она жива

Ключевая мысль: установка навыка package-tutorial-factory

Хватит теории — Мира открыла терминал, открывай и ты.

Пакет живёт на npm: страница @dzhechkov/skills-tutorial-factory, исходники — в публичном зеркале на GitHub. Установка навыка идёт через dz — тот же путь, что у любого пакета навыков:

  1. Поставь сам dz, если его ещё нет: npm i -g @dzhechkov/harness-cli.
  2. Разверни навык в проекте: dz init --target claude-code --select package-tutorial-factory.
  3. Проверь, что фабрика на месте: запусти извлекатель на любом пакете и посмотри на список тем.

Что означают части команды:
- dz init — раскладывает навыки в формат конкретного агента;
- --target claude-code — для какого агента собирать (поддерживаются и codex, и другие цели);
- --select package-tutorial-factory — какой навык взять. Один оркестратор тянет за собой все свои модули, справочники и скрипты.

Одна деталь, на которой Мира споткнулась. Скрипты фабрики вызываются не из корня проекта, а из установленного каталога навыка. Пакет требует держать путь в переменной SKILL_ROOT и вызывать скрипты так: node "$SKILL_ROOT/scripts/extract-brief.mjs". Мира сначала набрала просто node scripts/extract-brief.mjs, получила «файл не найден» и решила, что установка сломалась. Установка была цела — не тот путь.

Компромиссы: сильная сторона — навык самодостаточен: метод-база и все восемь исполняемых файлов лежат внутри его каталога, поэтому он переносится целиком. Слабая сторона — путь SKILL_ROOT придётся определить один раз руками, а вызовы из корня пакета, работавшие до версии 0.4.4, больше не работают.

💬 Просто попроси.
- «Поставь мне фабрику курсов» → ассистент подберёт команду dz init с нужной целью и навыком.
- «Не находит скрипт extract-brief» → ассистент напомнит про SKILL_ROOT и покажет правильную форму вызова.

3. Конвейер из шести шагов и две контрольные точки

Карта пути от пакета до проверенного сайта курса

Ключевая мысль: конвейер из шести шагов

Прежде чем нажимать кнопки, посмотри на карту целиком. Фабрика — это конвейер из шести шагов, и Мира ведёт по нему свой пакет ровно один раз, сверху вниз.

  1. Извлечение — по пакету собирается бриф: какие темы вообще можно преподавать.
  2. Написание курса — бриф превращается в объект курса; это единственный шаг, где всерьёз работает модель.
  3. Структурный гейт — детерминированная проверка без единого обращения к модели.
  4. Ревью на «дружелюбность к мозгу» — курс читает новый рецензент на другой модели и оценивает тон и историю.
  5. Рендер — объект курса превращается в один самодостаточный HTML-файл.
  6. Сдача — итоговая проверка по списку: гейт прошёл, права чисты, метод-база на месте, сайт запускается.

Между шагами стоят две контрольные точки — места, где конвейер останавливается и спрашивает человека:
- confirm-topics — после написания курса: «вот список тем, каждая со своим типом упражнения и ссылкой на приём метода. Согласен?»
- review-course — после рендера: «вот готовый курс, посмотри глазами».

Зачем останавливаться, если всё автоматизировано? Затем, что список тем — это решение о том, чему учить, а машина такие решения принимать не должна. Мира на первой контрольной точке выкинула две темы про устройство сборки: извлеклись они правильно, но новичку не нужны.

Компромиссы: сильная сторона — после гейта и до конца пути модель не вызывается ни разу, поэтому шаги 3, 5 и 6 воспроизводимы и годятся для непрерывной интеграции. Слабая сторона — конвейер линейный: если после рендера понял, что тема лишняя, возвращаешься к написанию курса и проходишь гейт заново.

💬 Просто попроси.
- «Покажи, из каких шагов состоит конвейер» → ассистент откроет карту шагов и объяснит, что даёт каждый.
- «Останови меня перед рендером» → ассистент доведёт до контрольной точки review-course и покажет курс до сборки сайта.

4. Шаг 1: извлечение концептуального брифа

Как пакет превращается в список тем и когда фабрика честно отказывается

Ключевая мысль: концептуальный бриф

Первый шаг вообще не обращается к модели. Скрипт extract-brief.mjs читает документацию пакета и составляет концептуальный бриф — список тем с зависимостями между ними.

Что попадает в бриф:
- каждый содержательный раздел README второго уровня — отдельная тема;
- каждый файл навыка SKILL.md — отдельная тема;
- обзорная тема на весь пакет и, если навыков нет, тема по программному интерфейсу из package.json.

Мира запустила его на своём пакете и получила семь тем. Разбор устроен аккуратно: заголовок внутри блока кода темой не станет, а служебные разделы вроде «Лицензия» и «История изменений» отсеиваются по списку исключений.

Самое интересное — когда фабрика отказывается работать. Решает не число тем, а объём содержательной документации, порог по умолчанию — 1500 знаков (вступление с бейджами в зачёт не идёт). Дальше два исхода:
- документации мало, но кода много → выход 3 и сигнал understand-anything: сначала разбери код другим навыком, его абстракции станут брифом;
- мало и того, и другого → выход 3 и сигнал insufficient-surface: остановиться и честно сказать «учить нечему». Курс из одной страницы не выпускается никогда.

Именно это и было исправлено в версии 0.3.0: раньше пакет без файлов навыков упирался в потолок из двух тем и всегда требовал разбора кода. После правки тот же harness-cli дал 18 тем без всякого отказа.

Компромиссы: сильная сторона — шаг быстрый, бесплатный и повторяемый, и отказ он выдаёт прямо, а не подсовывает тихую пустышку. Слабая сторона — извлекатель режет README только по заголовкам второго уровня, поэтому подтемы внутри больших разделов теряются, и автору курса приходится дочитывать README самому.

💬 Просто попроси.
- «Что вообще можно преподавать по этому пакету?» → ассистент соберёт концептуальный бриф и покажет список тем.
- «Хватит ли документации для курса?» → ассистент запустит извлекатель и скажет, проходит ли пакет порог или нужен разбор кода.

5. Шаг 2: объект курса course.json

Из чего состоит курс и почему каждая секция ссылается на приём метода

Ключевая мысль: объект курса course.json

Второй шаг — единственный, где всерьёз работает модель. На выходе один файл: объект курса course.json. Он же данные для сайта, он же вход для гейта — одна структура на две роли, поэтому расхождению взяться неоткуда.

Что обязано быть внутри:
- language, courseTitle, courseDescription — язык и заголовки;
- persona — один сквозной персонаж на весь курс (у нас это Мира);
- sections[] — минимум три секции, у каждой свой идентификатор, иконка, тип упражнения, ключевое понятие, теория, упражнение, вопрос финального теста и ссылка на приём метода;
- achievements[] — не меньше восьми наград, faqData[] — от пяти до восьми вопросов;
- topics[] — облегчённая проекция секций, которую строит функция toStepZero.

Типов упражнений ровно шесть: quiz, flashcards, matching, drag-and-drop, builder, scenario. Это не украшение, а требование метода: смена вида задания освежает внимание.

Ключевое правило этого шага — тройное кодирование. Одно понятие секции должно встретиться трижды: в теории, в упражнении и в вопросе финального теста. Мира сначала считала это бюрократией, пока не заметила: как только понятие исчезает из упражнения, секция превращается в текст, который читают глазами и не вспоминают.

И ещё одно: каждая секция обязана назвать приём метода, которому она служит — идентификатор вида P1–P12 или D1–D4 из метод-базы. Ссылка проверяется машиной, выдумать несуществующий приём нельзя.

Компромиссы: сильная сторона — контракт жёсткий, поэтому курс проверяем автоматически и его нельзя «почти сделать». Слабая сторона — шаг дорогой: это единственное место, где нужна сильная модель, и именно здесь курс получается живым или скучным.

💬 Просто попроси.
- «Собери курс по моему пакету на десять секций» → ассистент напишет объект курса и покажет список тем на подтверждение.
- «Разнообразь упражнения» → ассистент перераспределит типы упражнений так, чтобы подряд не шли одинаковые.

6. Шаг 3: детерминированный гейт

Тринадцать структурных проверок без единого обращения к модели

Ключевая мысль: детерминированный гейт

Третий шаг — детерминированный гейт: скрипт headfirst-gate.mjs читает объект курса и выносит вердикт. Ни одного обращения к модели, ни случайных чисел, ни текущей даты — поэтому один и тот же курс всегда получает один и тот же ответ, и проверку можно поставить в непрерывную интеграцию.

node "$SKILL_ROOT/scripts/headfirst-gate.mjs" --course course.json --json gate.json

Что он доказывает — тринадцать структурных свойств, среди них:
- у каждой секции есть непустое упражнение своего типа (пустая заготовка отвергается);
- подряд не идут три секции одного типа, а при шести и более секциях встречаются все шесть типов;
- понятие секции присутствует в теории, в упражнении и в финальном тесте;
- у каждой секции полная рефлексия: сильные стороны, слабые, оценка и итоговая фраза;
- имя персонажа встречается в каждой секции;
- наград не меньше восьми, все с разными условиями;
- ссылка на приём метода разрешается по метод-базе.

Две детали, которые Мира оценила не сразу. Во-первых, гейт отвергает невидимую пустоту: строка из одних лишь символов нулевой ширины не считается содержанием. Во-вторых, метод-база защищена от подмены: если подсунуть свою базу, где объявлен приём P99, гейт сверит её отпечаток с эталонным и откажется — подделать источник цитат нельзя.

И главное правило работы с гейтом: чинят курс, а не гейт. Красный вердикт — это найденный дефект курса, а не помеха. Мира однажды попробовала ослабить проверку, чтобы «пройти быстрее», и получила курс, где в двух секциях вообще не было упражнений.

Компромиссы: сильная сторона — определённость: свойство либо есть, либо нет, без мнений. Слабая сторона — гейт не судит смысл: он видит, что упражнение непустое, но не видит, что оно бессмысленное.

💬 Просто попроси.
- «Проверь курс гейтом» → ассистент запустит проверку и покажет список несоблюдённых свойств.
- «Гейт ругается на персонажа» → ассистент найдёт секции, где имя персонажа не встречается, и допишет их.

7. Шаг 4: семантическое ревью другой моделью

Кто судит тон, неожиданность и историю — и почему это отдельный слой

Ключевая мысль: семантическое ревью

Гейт сказал «прошло». Значит ли это, что курс хороший? Нет — и фабрика говорит об этом прямо, вместо того чтобы делать вид.

Проверки разнесены по двум уровням. Первый — структурный гейт: правило, определённость, ноль моделей. Второй — семантическое ревью: курс читает независимый рецензент на другой модели — он опирается на метод-базу и оценивает то, что правилом не решается:
- тон — обращаются ли к читателю на «ты», живая ли речь;
- неожиданность — есть ли поворот, шутка, момент «ага»;
- история — тянется ли сквозь курс сюжет с персонажем.

Скрипт brain-friendliness-prompt.mjs собирает для рецензента запрос, опирающийся на метод-базу. Внутрь встроены два правила честности:
1. Пустой или безоценочный ответ — это громкий отказ, а не чистое прохождение. Молчание рецензента никогда не считается похвалой.
2. Ревью советует, а не запрещает. Оно не блокирует выпуск автоматически, но конвейер считает курс готовым только после того, как ревью состоялось.

Почему рецензент — обязательно другая модель? Потому что тот, кто писал текст, читает его как автор: он видит замысел, а не то, что написано. Мира убедилась на своём курсе — её собственная вычитка нашла две шероховатости, чужая модель нашла девять, включая целую секцию, где персонаж исчезал ровно там, где становилось скучно.

Компромиссы: сильная сторона — ловится ровно то, чего правило не поймает никогда, и делается это независимым читателем. Слабая сторона — оценка модельная, значит нестабильная: два прогона могут разойтись, и это цена за суждение вместо правила.

💬 Просто попроси.
- «Проверь курс на живость» → ассистент соберёт запрос для семантического ревью и отправит его другой модели.
- «Рецензент ответил пусто» → ассистент сообщит об отказе, а не запишет молчание в успех.

8. Шаги 5–6: рендер и верификатор, который проходит курс

Один HTML-файл — и проверка не текста, а поведения

Ключевая мысль: верификатор проходит курс кликами

Вот место, где Мира удивилась сильнее всего.

Сначала обычное: render-site.mjs берёт прошедший гейт объект курса и собирает один самодостаточный HTML-файл. Он открывается прямо с диска, без сервера и без сети, и сборка детерминирована — тот же курс даёт те же байты.

node "$SKILL_ROOT/scripts/render-site.mjs" --course course.json --out site/index.html
node "$SKILL_ROOT/scripts/verify-site.mjs" --site site/index.html

А теперь неожиданное. Вторая команда не разбирает страницу и не ищет в ней слова. Верификатор проходит курс кликами: он запускает встроенный в страницу код в своей среде, открывает каждую секцию, выполняет каждое упражнение нажатиями, сдаёт финальный тест, жмёт «Сброс» — и после этого проверяет *сохранённое состояние*, а не текст на экране. Двадцать девять поведенческих проверок, выход 0 только если сошлись все.

Разница принципиальная. Проверка текста говорит «в HTML есть слово „пройдено“». Проверка поведения говорит «упражнение действительно засчиталось, а кнопка сброса действительно обнулила прогресс». Именно так нашлась ошибка, при которой «Сброс» ничего не делал: разметка была безупречной, поведение — сломанным.

Ещё две мелочи, которые видно на готовом сайте:
- подвал со ссылками — по умолчанию каналы мастерской, переопределяется полем footer.links; допускаются только адреса https, а подвал, из которого отфильтровались все ссылки, роняет проверку громко, а не исчезает молча;
- язык интерфейса — все служебные надписи лежат в одной таблице и выбираются по полю language, поэтому русский курс и читается, и проверяется по-русски.

Граница доверия — о ней надо знать. Верификатор исполняет код из переданного ему HTML. Это не песочница для чужих страниц: подавай ему только то, что собрала эта фабрика или другой доверенный источник.

Компромиссы: сильная сторона — зелёный результат означает «курс работает», а не «разметка валидна». Слабая сторона — цена в доверии: раз код исполняется, вход обязан быть проверенным.

💬 Просто попроси.
- «Собери сайт курса и проверь его» → ассистент выполнит рендер и запустит верификатор, показав число сошедшихся проверок.
- «Поменяй ссылки в подвале» → ассистент пропишет footer.links и напомнит, что принимаются только адреса https.

9. Права на книгу: что уезжает в пакет, а что остаётся дома

Метод-база, проверка на дословные совпадения и слоистая защита

Ключевая мысль: проверка на дословные совпадения

Метод Head First взят из книги, а книга защищена авторским правом. Как отдать метод и не отдать книгу?

Ответ фабрики — разделить две вещи. Методы и факты не охраняются авторским правом, охраняется их выражение. Поэтому наружу уезжает только пересказ приёмов: файл head-first-method.md, где каждый приём сформулирован своими словами и снабжён ссылкой на страницу первоисточника. Сам оцифрованный текст книги остаётся на машине, в git не попадает и в пакет не кладётся.

Защита сделана слоями, а не одним замком:
1. Автор пишет из очищенной базы. Модель видит пересказ, а не книгу, поэтому дословному тексту неоткуда взяться.
2. Корпус исключён из пакета структурно — список файлов пакета просто не содержит этих путей, это проверяется отдельным тестом.
3. Проверка на дословные совпадения. Скрипт shingling-check.mjs ищет любые совпадающие цепочки длиной от восьми слов между курсом и корпусом книги. Ноль совпадений — обязательное условие.

Мира спросила ровно то, что стоит спросить: «а если кто-то нарочно спрячет текст — переставит буквы, вставит невидимые символы?» Ответ записан в документации честно: это прямо объявлено вне области действия. Проверка защищает от обычного, не злонамеренного переиспользования; она не средство защиты от подделки и не судья.

Компромиссы: сильная сторона — три независимых слоя, и каждый работает сам по себе, поэтому пробой одного не открывает дверь. Слабая сторона — против целенаправленного обхода слои не рассчитаны, и об этом сказано вслух, а не замолчано.

💬 Просто попроси.
- «Проверь курс на дословные заимствования» → ассистент запустит проверку по корпусу и покажет результат.
- «Что из книги попадает в опубликованный пакет?» → ассистент покажет метод-базу и объяснит, почему корпус остаётся локальным.

10. Честные границы обещаний

Чего проверки не доказывают — и почему это написано прямо в README

Ключевая мысль: честные границы обещаний

Самый необычный раздел документации этого пакета называется «Область действия и честные ограничения». В нём написано, чего проверки не доказывают. Мира сначала решила, что это признание слабости. Потом поняла, что наоборот.

Вот эти честные границы обещаний — почти дословно:
- Проверки первого слоя доказывают структуру и чистоту прав, и только их: наличие, непустоту, разрешимость ссылок на метод, отсутствие дословных заимствований в тексте, написанном без злого умысла.
- Намеренно сделанный курс-пустышка структурный гейт пройти МОЖЕТ. Ловит его семантическое ревью — и поэтому конвейер требует, чтобы ревью состоялось до того, как курс считается готовым.
- Осмысленность и «настоящий ли это Head First по голосу» — свойство второго слоя, не первого.
- Подпись пакета удостоверяет собранный архив, а не отдельно скопированные файлы: каталог исходников считается неудостоверенным, пока архив не пересобран и не проверен.

Почему так написано? Потому что документированная граница — это защита от худшего вида ошибки: когда проверку считают сильнее, чем она есть, и перестают смотреть глазами. Гейт, про который думают «он ловит плохие курсы», опаснее отсутствия гейта: он раздаёт ложное спокойствие.

Есть и техническая причина сдержанности. Каждый раунд усиления проверок закрывал реальную дыру — и каждый же обнаруживал следующую, более хитрую. Это признак бесконечной погони: «осмысленно ли написано» правилом не решается в принципе. Разумный ход — назвать границу и поставить над ней второй слой, а не обещать невозможное.

Компромиссы: сильная сторона — читатель точно знает, на что опирается, а на что нет. Слабая сторона — честный список ограничений выглядит скромнее рекламного «полная проверка качества», и это осознанная плата.

💬 Просто попроси.
- «Что гейт НЕ доказывает?» → ассистент откроет раздел ограничений и перечислит границы по пунктам.
- «Можно ли считать зелёный гейт знаком качества?» → ассистент объяснит разницу между структурой и смыслом и напомнит про второй слой.

11. Собери собственный курс по своему пакету

Финальная сборка: решения принимаешь ты, конвейер только исполняет

Ключевая мысль: собственный курс по своему пакету

Последний шаг — твой. Мира свой курс уже собрала; теперь ты соберёшь собственный курс по своему пакету, и решения на развилках будут твоими.

Полный путь от начала до конца:

  1. Установи навык: dz init --target claude-code --select package-tutorial-factory.
  2. Извлеки бриф: node "$SKILL_ROOT/scripts/extract-brief.mjs" --pkg <каталог пакета> --json brief.json.
  3. Напиши объект курса и подтверди список тем на контрольной точке.
  4. Прогони гейт: node "$SKILL_ROOT/scripts/headfirst-gate.mjs" --course course.json --json gate.json.
  5. Отдай курс на семантическое ревью другой модели.
  6. Собери и проверь сайт: render-site.mjs, затем verify-site.mjs.

Три решения, которые никто за тебя не примет:
- Сколько секций. Извлекатель показывает всё, что нашёл; сколько из этого нужно новичку — вопрос к автору. Мира из семи тем сделала одиннадцать секций, разбив две крупные.
- Кто персонаж. Одно имя на весь курс, и оно обязано встречаться в каждой секции — иначе история рвётся ровно там, где становится трудно.
- Где остановиться. Иногда честный ответ — «учить нечему»: тогда пиши указатель в файле навыка, а не курс.

И правило, которое стоит унести с собой целиком: чинят курс, а не проверку. Красный гейт — это подарок, найденный дефект. Ослабленный гейт — это тот же дефект, только теперь невидимый.

Компромиссы: сильная сторона — путь короткий, и после написания курса всё повторяемо. Слабая сторона — качество упирается в один шаг: сколько вложишь в написание курса, столько и получит читатель, а конвейер лишь не даст выпустить сломанное.

💬 Просто попроси.
- «Сделай курс по моему пакету на десять секций» → ассистент пройдёт весь конвейер и остановится на контрольных точках.
- «Проверь мой курс целиком перед публикацией» → ассистент прогонит гейт, проверку прав и запуск сайта и покажет сводку.

Частые вопросы

Нужно ли ставить весь harness, чтобы пользоваться фабрикой курсов?

Нужен dz — через него навык раскладывается в формат твоего агента: npm i -g @dzhechkov/harness-cli, затем dz init --target claude-code --select package-tutorial-factory. Сами скрипты фабрики зависимостей не требуют: только Node и встроенные модули.

Курс обязательно должен быть на русском?

Нет. Язык задаётся полем language объекта курса. Значение ru включает русские надписи интерфейса целиком; любое другое значение оставляет английские. Названия команд не переводятся ни при каком языке.

Сколько секций должно быть в курсе?

Минимум три по контракту, разумный рабочий диапазон — восемь–двенадцать. При шести и более секциях гейт требует, чтобы встречались все шесть типов упражнений, поэтому слишком короткий курс теряет разнообразие.

Что делать, если извлекатель отказался работать?

Смотри сигнал: understand-anything означает «документации мало, но код большой» — разбери код соответствующим навыком и используй его абстракции как бриф. insufficient-surface означает «учить нечему» — остановись и скажи это честно, курс из одной темы не выпускается.

Гейт зелёный — значит курс хороший?

Нет. Зелёный гейт означает, что выполнены структурные свойства: упражнения непустые, понятия повторены трижды, персонаж есть в каждой секции, ссылки на метод разрешаются. Живость текста оценивает семантическое ревью другой моделью, и конвейер считает курс готовым только после него.

Можно ли изменить сам метод обучения?

Да, и для этого не надо трогать код: метод лежит в файле head-first-method.md, приёмы P1–P12 и D1–D4 берутся оттуда во время работы. Правишь файл — меняется метод. Но гейт сверяет отпечаток базы с эталонной, поэтому подменить её на ходу, чтобы прошли выдуманные ссылки, не получится.

Безопасно ли запускать верификатор на чужом HTML?

Нет. Верификатор исполняет код из переданной страницы в своей среде — это проверка поведения, а не песочница. Подавай ему только то, что собрала эта фабрика или другой доверенный источник.

Бесплатный интерактивный курс · aicoding.space

Лицензии шрифтов

Onest

Copyright 2021 The Onest Project Authors (https://github.com/googlefonts/onest)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded, 
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

JetBrainsMono

Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded, 
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.