{
  "version": 1,
  "title": "Функции формул vMix JSON — хоккей",
  "description": "Справочник функций для вычисляемых колонок хоккейных vMix JSON.",
  "categories": [
    {
      "title": "Поля и сборка строк",
      "items": [
        {
          "name": "get",
          "example": "get('player')",
          "description": "Взять поле по имени. Если поля нет — пустая строка."
        },
        {
          "name": "val",
          "example": "val('total', '-')",
          "description": "То же самое, что get()."
        },
        {
          "name": "concat",
          "example": "concat(position, '. ', player)",
          "description": "Склеить значения без разделителя."
        },
        {
          "name": "join",
          "example": "join(' / ', player, club, total)",
          "description": "Склеить только заполненные значения через разделитель."
        },
        {
          "name": "tpl",
          "example": "tpl('#{position} {player}  {total}')",
          "description": "Шаблон с подстановкой полей в фигурных скобках."
        },
        {
          "name": "coalesce",
          "example": "coalesce(player, name, '-')",
          "description": "Первое непустое значение."
        }
      ]
    },
    {
      "title": "Текст",
      "items": [
        {
          "name": "split",
          "example": "split(player, ' ', 0)",
          "description": "Разбить строку и взять часть по индексу."
        },
        {
          "name": "part",
          "example": "part(player, ' ', 1)",
          "description": "Короткий вариант split(value, sep, index)."
        },
        {
          "name": "left",
          "example": "left(player, 3)",
          "description": "Первые N символов."
        },
        {
          "name": "right",
          "example": "right(player, 3)",
          "description": "Последние N символов."
        },
        {
          "name": "mid",
          "example": "mid(player, 2, 4)",
          "description": "Фрагмент строки."
        },
        {
          "name": "replace",
          "example": "replace(player, '  ', ' ')",
          "description": "Обычная замена текста."
        },
        {
          "name": "upper/lower/title/strip",
          "example": "upper(country)",
          "description": "Регистр и очистка пробелов."
        },
        {
          "name": "swap",
          "example": "swap(player)",
          "description": "Поменять порядок частей строки: Иван Петров → Петров Иван."
        }
      ]
    },
    {
      "title": "Условия",
      "items": [
        {
          "name": "case / iif",
          "example": "case(to_par == 0, 'E', to_par)",
          "description": "Если условие истинно — первое значение, иначе второе."
        },
        {
          "name": "empty / filled",
          "example": "if_empty(total, '-', total)",
          "description": "Проверка пустого/заполненного значения."
        },
        {
          "name": "if_empty",
          "example": "if_empty(thru, '—', thru)",
          "description": "Если пусто."
        },
        {
          "name": "if_filled",
          "example": "if_filled(country, country, '')",
          "description": "Если заполнено."
        },
        {
          "name": "if_contains",
          "example": "if_contains(status, 'active', 'LIVE', '')",
          "description": "Если строка содержит текст."
        },
        {
          "name": "if_not_contains",
          "example": "if_not_contains(status, 'active', '', 'LIVE')",
          "description": "Если строка не содержит текст."
        },
        {
          "name": "if_equals / if_eq",
          "example": "if_eq(to_par, '0', 'E', to_par)",
          "description": "Если значение равно ожидаемому."
        },
        {
          "name": "if_field_empty",
          "example": "if_field_empty('today', '-', today)",
          "description": "Проверить поле по имени."
        }
      ]
    },
    {
      "title": "Поиск и Regex",
      "items": [
        {
          "name": "contains",
          "example": "contains(player, 'Иван')",
          "description": "True/False: содержит текст."
        },
        {
          "name": "starts / ends",
          "example": "starts(player, 'A')",
          "description": "Начинается/заканчивается на текст."
        },
        {
          "name": "regex / match",
          "example": "regex(player, '^A')",
          "description": "Проверка регулярным выражением."
        },
        {
          "name": "if_regex",
          "example": "if_regex(player, '^A', 'A', '')",
          "description": "Условие по регулярному выражению."
        },
        {
          "name": "re_replace",
          "example": "re_replace(title, '(\\d)(?=(\\d{3})+\\b)', '\\1.')",
          "description": "Regex-замена."
        },
        {
          "name": "re_replace_first",
          "example": "re_replace_first(text, '\\s+', ' ')",
          "description": "Заменить только первое совпадение."
        },
        {
          "name": "re_remove",
          "example": "re_remove(player, '\\s+')",
          "description": "Удалить по regex."
        },
        {
          "name": "re_extract",
          "example": "re_extract(player, '#(\\d+)', 1)",
          "description": "Достать группу из текста."
        },
        {
          "name": "first_match",
          "example": "first_match(title, {'СБ':'Барьеры', 'Бег':'Бег'}, '')",
          "description": "Первое совпавшее правило."
        }
      ]
    },
    {
      "title": "Числа, время, даты",
      "items": [
        {
          "name": "number / num",
          "example": "number(total, 0)",
          "description": "Преобразовать в число."
        },
        {
          "name": "int/float/round/min/max/abs/sum",
          "example": "round(number(total), 1)",
          "description": "Базовая математика Python."
        },
        {
          "name": "format_thousands",
          "example": "format_thousands(10000)",
          "description": "10.000."
        },
        {
          "name": "format_distance",
          "example": "format_distance('10000')",
          "description": "Формат дистанций: 10.000."
        },
        {
          "name": "time_seconds",
          "example": "time_seconds('1:02.34')",
          "description": "Время в секунды."
        },
        {
          "name": "format_time",
          "example": "format_time(62.34, 'auto_tt')",
          "description": "Секунды обратно во время."
        },
        {
          "name": "time_diff",
          "example": "time_diff(result, leader, 'auto_tt')",
          "description": "Разница двух времен."
        },
        {
          "name": "today",
          "example": "today('%d.%m.%Y')",
          "description": "Сегодняшняя дата."
        },
        {
          "name": "age / age_at",
          "example": "age_at(birthDate, today())",
          "description": "Возраст по дате рождения."
        },
        {
          "name": "birth_year",
          "example": "birth_year(birthDate)",
          "description": "Год рождения."
        }
      ]
    },
    {
      "title": "Склейка JSON",
      "items": [
        {
          "name": "match",
          "example": "player_id=id",
          "description": "Сопоставление ключей: слева поле основного JSON, справа поле подключаемого источника."
        },
        {
          "name": "fields",
          "example": "club=club\\ncountry=country",
          "description": "Какие поля подтянуть: слева новое имя поля, справа поле источника."
        },
        {
          "name": "multiple",
          "example": "first / last / all / count",
          "description": "Что делать, если найдено несколько совпадений."
        },
        {
          "name": "source_type",
          "example": "scores / tournament / round / vmix_json / url",
          "description": "Тип подключаемого источника данных."
        }
      ]
    },
    {
      "title": "Вертикальные вычисления по таблице",
      "items": [
        {
          "name": "max",
          "example": "max('total')",
          "description": "Максимальное числовое значение колонки по всем строкам текущей таблицы. Для обычных чисел max(1, 2) тоже работает."
        },
        {
          "name": "min",
          "example": "min('total')",
          "description": "Минимальное числовое значение колонки по всем строкам текущей таблицы."
        },
        {
          "name": "avg / average / mean",
          "example": "avg('total')",
          "description": "Среднее числовое значение колонки по всем строкам текущей таблицы."
        },
        {
          "name": "values",
          "example": "values('total')",
          "description": "Список числовых значений колонки по всем строкам. Можно использовать в своих формулах."
        },
        {
          "name": "first_value / first",
          "example": "first_value('total')",
          "description": "Значение колонки из первой строки таблицы после сортировки/подготовки данных."
        },
        {
          "name": "diff_first / diff_from_first",
          "example": "diff_first('total', 2)",
          "description": "Разница между значением текущей строки и первой строки: current - first. Второй аргумент — округление."
        },
        {
          "name": "gap_first / gap_from_first",
          "example": "gap_first('total', 2)",
          "description": "То же, что diff_first(), но сразу форматирует со знаком +/-. Удобно для отставаний."
        },
        {
          "name": "row_index / row_number",
          "example": "row_number()",
          "description": "Номер текущей строки: row_index() с нуля, row_number() с единицы."
        }
      ]
    }
  ]
}