Начни здесь

trip-planner: поездка → мобильный сайт-маршрут

Курс по пакету @dzhechkov/trip-planner для участников harness-мастерской. За двенадцать разделов ты пройдёшь путь Миры: от вороха вкладок про Казань до одного самодостаточного HTML-файла с днями, картами, погодой и проверенными контактами — и разберёшься, какие правила честности стоят за этим файлом.

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

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

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

1. Зачем нужен trip-planner

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

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

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

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

Пакет @dzhechkov/trip-planner решает именно эту задачу. Ты описываешь поездку словами — город, даты, время приезда и отъезда, адрес жилья, состав компании, ограничения, — а получаешь мобильный сайт-маршрут: один HTML-файл, который открывается на телефоне и работает без интернета.

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

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

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

💬 Просто попроси.
- «Что умеет trip-planner?» → ассистент откроет README пакета и перескажет, что получается на выходе.
- «Хочу мобильный сайт-маршрут по Казани на три дня» → ассистент запустит навык trip-planner и начнёт с уточняющих вопросов о поездке.

2. Установка: npx, предпросмотр и поддержка других ассистентов

Как поставить набор в проект и как заглянуть внутрь, ничего не записав

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

Мира открывает пустую папку проекта и хочет действовать осторожно: сначала посмотреть, что появится на диске, и только потом что-то записывать.

Установка идёт через npx — глобально ставить ничего не нужно. Одна команда копирует набор в каталог .claude/ текущего проекта:

  1. npx @dzhechkov/trip-planner init — установка набора: четыре навыка, команда /trip-planner, правило и контекстный фрагмент;
  2. npx @dzhechkov/trip-planner init --dry-run — предпросмотр: печатает, что было бы скопировано, и не пишет ни байта;
  3. npx @dzhechkov/trip-planner init --force — перезапись, если набор в этой папке уже стоит.

Есть второй путь — через общий установщик @dzhechkov/harness-cli: npm install -g @dzhechkov/harness-cli, затем dz install @dzhechkov/trip-planner --target hermes. Он нужен, когда ты работаешь не в Claude Code, а в другом ассистенте: тот же канонический SKILL.md проецируется в его каталог, например .hermes/skills/trip-planner/.

После установки в Claude Code достаточно написать /trip-planner Казань 3 дня, 10–12 июля, приезд 10:30 поезд, отъезд 21:00 самолёт, жильё ул. Баумана 1, 2 чел (с ребёнком 5 лет), без алкоголя, вегетарианцы, бюджет 4000₽/день — или просто описать поездку словами: навык подхватится сам.

Страница пакета: npmjs.com/package/@dzhechkov/trip-planner, зеркало исходников: github.com/djd1m/dz-harness.

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

💬 Просто попроси.
- «Поставь trip-planner в этот проект» → ассистент выполнит npx @dzhechkov/trip-planner init и покажет список скопированных файлов.
- «Сначала покажи, что установится» → ассистент прогонит init --dry-run и напечатает план без записи на диск.

3. Команды набора: init, list, doctor

Четыре команды установщика и то, в какой момент каждая из них выручает

Ключевая мысль: команды init, list и doctor

У установщика ровно три рабочих команды, и Мира выучивает их за минуту, потому что каждая отвечает на один вопрос.

  • init — «поставь». Команда по умолчанию: запуск без аргументов означает именно её. Копирует навыки, команду /trip-planner, правило и фрагмент контекста в .claude/, а рядом кладёт манифест .trip-planner.json — список всего, что было записано.
  • list — «что внутри». Печатает навыки, которые входят в набор, ничего не устанавливая; удобно заглянуть, прежде чем решишь ставить.
  • doctor — «цело ли». Читает манифест и проверяет, что каждый записанный файл на месте. Если файла нет — значит, его удалили или перезаписали; лечится init --force.

К ним два модификатора: --dry-run (предпросмотр без записи) и --force (разрешить перезапись). Незнакомый флаг установщик не проглатывает молча: опечатка вроде --froce останавливает запуск с ошибкой, а не тихо превращается в установку без перезаписи.

Почему это важно. Тихая подмена — худший вид ошибки: ты уверен, что запустил перезапись, а на диске остались старые файлы. Громкий отказ дешевле разбирательства через неделю.

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

💬 Просто попроси.
- «Проверь, цел ли установленный trip-planner» → ассистент выполнит doctor и покажет пропавшие файлы, если они есть.
- «Какие навыки входят в набор?» → ассистент выполнит list и перечислит их.

4. Что именно получается на выходе

Один файл и восемь обязательных свойств сайта

Ключевая мысль: самодостаточный HTML-файл

Результат работы — самодостаточный HTML-файл по пути trip/<город>/index.html. Самодостаточный значит буквально: стили и скрипты лежат внутри самого файла, сборки нет, внешних библиотек нет.

Вот как он устроен, если нарисовать схему словами:

  index.html
  ├── закреплённая навигация        ← День 1 · День 2 · День 3
  ├── День 1
  │    ├── погода + совет по одежде  ← считается прямо на странице
  │    ├── ссылка «маршрут дня»      ← все точки дня одной ссылкой
  │    └── карточки точек            ← нажми → время, цена, советы
  │         └── у заведения: адрес, телефон/сайт, отзывы, дата проверки
  └── День 2, День 3 …

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

Единственный запрос в сеть у готовой страницы — прогноз погоды. Пропал интернет — страница остаётся рабочей, исчезает только прогноз.

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

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

5. Бриф поездки: о чём тебя спросят и почему

Семь обязательных полей и что ломается, когда одного не хватает

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

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

Семь обязательных полей:
1. город и число дней — сколько будет вкладок с днями;
2. даты — по ним запрашивается прогноз погоды;
3. прибытие — время и способ; первый день начинается после реального приезда, а не в девять утра;
4. отъезд — последний день заканчивается до выезда, с запасом на дорогу;
5. адрес жилья — точка старта и финиша каждого дня, к ней привязывается маршрут;
6. количество человек — влияет на бюджет и выбор заведений;
7. ограничения — алкоголь, вегетарианство, дети, бюджет в день, подвижность.

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

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

💬 Просто попроси.
- «Составь бриф поездки по моему сообщению и скажи, чего не хватает» → ассистент разложит текст по семи полям и назовёт пробелы.
- «Приезд в 22:40, что это меняет?» → ассистент объяснит, что первый день сжимается до ужина рядом с жильём.

6. Конвейер из пяти шагов

Сбор брифа → исследование → маршрут → сайт → валидация

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

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

  1. Сбор брифа (навык explore) — семь обязательных полей и явные ограничения.
  2. Исследование (навык goap-research-ed25519) — точки и заведения с координатами, часами работы, контактами, ссылками на отзывы и пометкой о предварительной брони; ограничения уже здесь работают как фильтр.
  3. Маршрут — раскладка точек по дням с учётом времени приезда и отъезда, порядок внутри дня подбирается так, чтобы не возвращаться по своим следам.
  4. Сайт (навык frontend-design) — шаблон страницы заполняется данными маршрута.
  5. Валидация — чек-лист: нет ли точки без координат, заведения без контактов, дня без маршрута и погоды.

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

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

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

7. Ограничения — жёсткие фильтры, а не пожелания

Почему «без алкоголя» отсекает варианты, а не превращается в сноску

Ключевая мысль: жёсткие фильтры

Ограничения Миры — «без алкоголя, вегетарианцы, с ребёнком пяти лет, бюджет 4000 ₽ в день» — в этом пакете работают как жёсткие фильтры.

Жёсткие фильтры означают: кандидат, нарушающий условие, не попадает в план вовсе. Не попадает с пометкой, не попадает со сноской «уточните на месте» — просто заменяется другим. Разница видна на примере: ресторан с одним мясным меню при мягком подходе оказался бы в списке с примечанием, и Мира с ребёнком пришла бы туда голодной.

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

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

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

💬 Просто попроси.
- «Добавь ограничение: без лестниц, едем с коляской» → ассистент внесёт его в бриф и перестроит маршрут.
- «Почему в плане нет этого ресторана?» → ассистент назовёт нарушенное ограничение, из-за которого он отсеян.

8. Проверенные контакты и запрет на выдуманные данные

Правило доказательства: адрес, связь, отзыв с датой — или замена

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

Самая опасная ошибка планировщика — правдоподобная выдумка. Координаты «примерно там», телефон «наверное такой», рейтинг «где-то 4,6» выглядят как данные и ведут себя как данные, пока Мира не приедет по этому адресу и не обнаружит там шиномонтаж.

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

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

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

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

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

9. Карты и погода: порядок координат решает всё

Метка, маршрут дня и прогноз без единого ключа доступа

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

Во внешний мир готовый файл выходит только в двух местах — за картами и за погодой, — и ни там, ни там не нужен ключ доступа.

Карты — это просто ссылки. У Яндекс.Карт две схемы, и координаты в них идут в разном порядке — это главная ловушка раздела:
- метка одной точки: ?pt=долгота,широта — сначала долгота;
- маршрут дня: ?rtext=широта,долгота~широта,долгота — сначала широта, а точки разделяет тильда; тип пути задаёт rtt (pd пешком, auto на машине, mt на транспорте).

Перепутанный порядок не даёт ошибки: ссылка открывается и показывает уверенно неверное место — Мира однажды получила вместо Кремля точку в Индийском океане. Поэтому в чек-листе валидации есть отдельная строка про порядок координат.

Погода — запрос к Open-Meteo прямо со страницы. Сервис открыт для запросов из браузера и не требует ключа, поэтому файл остаётся самодостаточным: никакого сервера, никакого секрета внутри. Совет по одежде страница считает сама, по температуре и осадкам, — отдельного запроса на это нет. Нет сети — блок погоды аккуратно исчезает, остальное работает.

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

💬 Просто попроси.
- «Проверь ссылки на карты в маршруте» → ассистент сверит порядок координат в метках и маршрутах дней.
- «Сделай маршрут дня пешеходным» → ассистент выставит rtt=pd в ссылке маршрута.

10. Валидация: чек-лист, который решает — готово или нет

Семь проверок последнего шага и что каждая ловит

Ключевая мысль: валидация маршрута

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

Что проверяется:
1. Каждая точка — есть координаты, ссылка-метка, стоимость и отметка о необходимости брони.
2. Каждое названное заведение — адрес, сайт или телефон, ссылка на отзывы и дата проверки.
3. Каждый день — рабочая ссылка на маршрут по всем точкам дня, блок погоды и совет по одежде.
4. Ограничения — соблюдены в каждом выборе, без исключений «ну почти».
5. Разнообразие — в поездке есть экскурсии, музеи, прогулки, смотровые площадки, вода и местная кухня; план целиком из музеев не проходит.
6. Мобильность — открывается одной рукой, нет горизонтальной прокрутки, карточки раскрываются.
7. Дни приезда и отъезда — укладываются в реальные транспортные окна.

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

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

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

11. Самообучение исследовательского навыка

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

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

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

Механика простая. Если в системе установлен @dzhechkov/harness-cli, навык в начале исследования вспоминает ранее записанные уроки о методе — как искать, каким источникам верить, где обычно ошибался, — и записывает новые в четырёх заранее названных точках прогона. Инструмент подхватывается, если он есть, но не требуется: если его нет, навык один раз честно сообщает об этом и работает как обычно.

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

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

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

💬 Просто попроси.
- «Включено ли самообучение исследования?» → ассистент проверит наличие harness-cli и скажет, работают ли уроки.
- «Какие уроки о методе поиска уже накоплены?» → ассистент выберет уроки из хранилища и перескажет главные.

12. Границы: когда trip-planner не тот инструмент

Три соседних навыка и честный список ограничений пакета

Ключевая мысль: границы применения

Инструмент, у которого нет описанных границ, обычно применяют не по назначению. У trip-planner границы названы прямо в описании навыка, и Мира заканчивает курс именно ими.

Когда нужен не он, а сосед:
- исследование без дат и логистики («что вообще интересного в Казани?») → навык goap-research-ed25519 напрямую: он ищет и проверяет, но не раскладывает по дням;
- обычная информационная страница, не маршрут → навык frontend-design;
- учебный сайт или курс → генератор учебных сайтов, а для расшифровки беседы есть свой отдельный генератор.

Честные ограничения самого пакета:
1. результат — снимок на момент сборки: часы работы и цены сами не обновятся;
2. карты завязаны на Яндекс — за пределами России польза заметно падает;
3. качество плана целиком зависит от шага исследования: не нашлись проверенные контакты — заведение выпадает, даже если оно прекрасное;
4. строгие ограничения в маленьком городе могут оставить очень узкий выбор;
5. единственный живой запрос страницы — погода, всё остальное зафиксировано в файле.

Вывод, который стоит унести с собой. Ценность пакета не в том, что он «знает города», а в том, что он отказывается врать: не выдумывает координаты, не смягчает ограничения молча и не выдаёт непроверенное за проверенное. Именно поэтому итоговому файлу можно доверять в дороге.

💬 Просто попроси.
- «Мне нужен просто обзор города без дат» → ассистент предложит навык исследования вместо trip-planner.
- «Обнови маршрут: часы музея изменились» → ассистент перезапустит шаги исследования и сборки для этой точки.

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

Нужен ли ключ доступа к картам или погоде?

Нет. Яндекс.Карты открываются обычной ссылкой, а прогноз запрашивается у Open-Meteo прямо из страницы — сервис не требует ключа. Поэтому готовый файл остаётся самодостаточным: внутри него нет ни одного секрета.

Что будет, если я не укажу время приезда?

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

Можно ли пользоваться пакетом не в Claude Code?

Да. Поставь общий установщик командой npm install -g @dzhechkov/harness-cli и выполни dz install @dzhechkov/trip-planner --target hermes. Канонический SKILL.md остаётся прежним — он лишь проецируется в каталог другого ассистента.

Почему из плана пропало заведение, которое мне советовали?

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

Файл будет обновляться, если у музея изменятся часы работы?

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

Что делает doctor и когда он нужен?

Он читает манифест .trip-planner.json и проверяет, что все записанные файлы на месте. Он нужен, когда команда /trip-planner перестала находиться или навыки начали вести себя странно. Лечится повторной установкой с флагом --force.

Бесплатный интерактивный курс · 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.