% \iffalse meta-comment
% ^^A  -*- coding: utf-8 -*-
%
% iptconf.dtx  ---  Document class for IPT conference proceedings
%
% Copyright (C) 2015--2026 Sergiy Ponomarenko
%                          <s.ponomarenko@kpi.ua>
%
% This file may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either
% version 1.3c of this license or (at your option) any later
% version. The latest version of this license is in:
%
%     https://www.latex-project.org/lppl.txt
%
% and version 1.3c or later is part of all distributions of
% LaTeX version 2008 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Sergiy Ponomarenko.
%
% This work consists of the files iptconf.dtx and iptconf.ins
% and the derived file iptconf.cls.
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{iptconf.dtx}[2026/05/24 v1.0 IPT conference class]
\documentclass{l3doc}
\usepackage{fontspec}
  \setmainfont{CMU Serif}
  \setmonofont{CMU Typewriter Text}
  \setsansfont{CMU Sans Serif}
\usepackage[ukrainian, russian, english]{babel}
\usepackage{microtype}
\usepackage{hologo}
\usepackage{csquotes}
\usepackage{enumitem}
\setlist{noitemsep}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
  \DocInput{iptconf.dtx}
  \PrintChanges
  \clearpage
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \changes{v1.0}{2026/05/24}{First public release on CTAN}
%
% \GetFileInfo{iptconf.dtx}
%
% \DoNotIndex{\newcommand,\renewcommand,\providecommand}
% \DoNotIndex{\begin,\end,\par,\noindent,\vskip,\vspace}
% \DoNotIndex{\if,\else,\fi,\ifnum,\iflanguage}
% \DoNotIndex{\@ne,\z@,\@empty,\@maketitle}
%
%^^A ===========================================================
% \title{%
%   The \pkg{iptconf} class\thanks{This document describes
%   \pkg{iptconf}~\fileversion, last revised~\filedate.}
% }
% \author{%
%   Sergiy Ponomarenko\\
%   \href{mailto:s.ponomarenko@kpi.ua}
%        {\texttt{s.ponomarenko@kpi.ua}}\\
%   Institute of Physics and Technology,\\
%   Igor Sikorsky Kyiv Polytechnic Institute
% }
% \date{Released \filedate}
%
% \maketitle
%
% \begin{abstract}
%   \noindent
%   The \pkg{iptconf} class provides a two-column, A4 document layout
%   for papers submitted to the annual conference of the Institute of
%   Physics and Technology (IPT / НН\,ФТІ) at Igor Sikorsky Kyiv
%   Polytechnic Institute.  The class supports Ukrainian, Russian and
%   English as the paper language; automatically writes a speaker
%   registration form (\texttt{.txt}) and structured article metadata
%   (\texttt{.yaml}) as side effects of |\PaperLanguage|; and exports
%   per-paper title/author data to a \texttt{.dat} auxiliary file
%   suitable for building a book-of-abstracts index.
%   The class requires \hologo{LuaLaTeX} or \hologo{XeLaTeX} for full
%   functionality; \hologo{pdfLaTeX} is supported with reduced font
%   features.
% \end{abstract}
%
% \tableofcontents
%
%^^A ===========================================================
% \section{Introduction}
%
% The \pkg{iptconf} class was created to provide a uniform appearance
% for papers in the IPT conference proceedings while also automating
% the collection of metadata needed for the conference organisers.
% It wraps the standard \cls{article} class in two-column mode and
% adds:
%
% \begin{itemize}
%   \item A structured title block with multiple authors, numbered
%         affiliations, and optional per-author e-mail footnotes.
%   \item Language-aware strings (bibliography heading, keyword label,
%         etc.) for Ukrainian, Russian and English via the
%         |\newlanguagecommand| mechanism.
%   \item A speaker registration form written to
%         \texttt{\textit{jobname}-regform.txt}.
%   \item Structured YAML article metadata written to
%         \texttt{\textit{jobname}-info.yaml}.
%   \item A \texttt{\textit{jobname}.dat} auxiliary file recording
%         |\thispapertitle| and |\thispaperauthor| entries for use by
%         a book-of-abstracts driver.
%   \item \pkg{biblatex} with the \texttt{gost-numeric} style,
%         automatic language-sensitive bibliography heading.
%   \item Balanced two-column output via \pkg{flushend}.
% \end{itemize}
%
%^^A ===========================================================
% \section{Package requirements}
%
% The class requires a reasonably modern \LaTeX{} installation
% (kernel 2022-06-01 or later).  The following packages must be
% available:
%
% \begin{itemize}
%   \item \pkg{geometry} --- page layout.
%   \item \pkg{xcolor} --- colour support.
%   \item \pkg{mathtools}, \pkg{amssymb} --- mathematics.
%   \item \pkg{fontsetup} (Lua\LaTeX/\hologo{XeLaTeX}) or
%         \pkg{fontenc}/\texttt{opensans} (\hologo{pdfLaTeX}).
%   \item \pkg{microtype} --- micro-typographic enhancements.
%   \item \pkg{csquotes}, \pkg{babel} --- language support.
%   \item \pkg{biblatex} with \pkg{biber} and the
%         \texttt{biblatex-gost} bundle.
%   \item \pkg{enumitem} --- list customisation.
%   \item \pkg{flushend} --- balanced columns on the last page.
%   \item \pkg{subcaption}, \pkg{caption} --- figure/table captions.
%   \item \pkg{hyperref} --- PDF hyperlinks and bookmarks.
% \end{itemize}
%
%^^A ===========================================================
% \section{Usage}
%
% \subsection{Minimal document}
%
% \begin{verbatim}
% \documentclass[single=3]{iptconf}   % standalone, starting at page 3
%
% \title{Title of the Paper}
%
% \author[speaker@uni.edu]{First Speaker}{1,2}
% \author{Second Author}{1}
%
% \affiliation{\ipt}{1}
% \affiliation{Another University}{2}
%
% \udc{537.8}
% \pacs{41.20.-q}
% \keywords{Maxwell equations, wave propagation}
% \abstract{Short abstract text.}
%
% \regform{
%   fullname       = Petro Ivanovych Kovalenko,
%   birthday       = 01.01.1990,
%   position       = PhD student,
%   phone          = +380501234567,
%   authoremail    = speaker@uni.edu,
%   confsection    = Section A,
%   copynum        = 1,
%   needliving     = no,
%   needinvitanion = no,
% }
%
% \begin{document}
% \PaperLanguage{ukrainian}
%
% \section{Introduction}
% ...
%
% \end{document}
% \end{verbatim}
%
% \subsection{Class options}
%
% \begin{function}{incollection}
%   \begin{syntax}
%     \cs{documentclass}\oarg{incollection}\{iptconf\}
%   \end{syntax}
%   Default mode.  Page numbers are suppressed (|\pagestyle{empty}|),
%   as the paper will be incorporated into a proceedings volume.
% \end{function}
%
% \begin{function}{single}
%   \begin{syntax}
%     \cs{documentclass}\oarg{single=\meta{n}}\{iptconf\}
%   \end{syntax}
%   Standalone mode with page numbers starting at \meta{n} (default~1).
%   Use this option when compiling the paper outside the proceedings.
% \end{function}
%
% \subsection{Preamble commands}
%
% \begin{function}{\title}
%   \begin{syntax}
%     \cs{title}\marg{text}
%   \end{syntax}
%   Sets the paper title.  The title is stored internally and also
%   written to \texttt{\textit{jobname}.dat} as
%   |\thispapertitle|\marg{text}.
% \end{function}
%
% \begin{function}{\author}
%   \begin{syntax}
%     \cs{author}\oarg{email}\marg{name}\marg{affil-index}
%   \end{syntax}
%   Adds an author.  \meta{affil-index} is a comma-separated list of
%   affiliation numbers (e.g.\ |1,2|).  The optional \meta{email}
%   appears as a footnote.  Each call also appends
%   |\thispaperauthor|\marg{name} to \texttt{\textit{jobname}.dat}.
% \end{function}
%
% \begin{function}{\affiliation}
%   \begin{syntax}
%     \cs{affiliation}\marg{institution}\marg{number}
%   \end{syntax}
%   Registers an affiliation with superscript \meta{number}.  The
%   token |\ipt| may be used for the full Ukrainian name of the
%   institute; it is collapsed to the abbreviation \enquote{НН\,ФТІ}
%   in the YAML output.
% \end{function}
%
% \begin{function}{\udc}
%   \begin{syntax}
%     \cs{udc}\marg{code}
%   \end{syntax}
%   Stores the UDC (Universal Decimal Classification) code.
% \end{function}
%
% \begin{function}{\pacs}
%   \begin{syntax}
%     \cs{pacs}\marg{codes}
%   \end{syntax}
%   Stores PACS (Physics and Astronomy Classification Scheme) codes.
% \end{function}
%
% \begin{function}{\keywords}
%   \begin{syntax}
%     \cs{keywords}\marg{list}
%   \end{syntax}
%   Stores the keyword list, printed below the abstract.
% \end{function}
%
% \begin{function}{\abstract}
%   \begin{syntax}
%     \cs{abstract}\marg{text}
%   \end{syntax}
%   Stores the abstract text (printed as part of |\maketitle|).
% \end{function}
%
% \begin{function}{\regform}
%   \begin{syntax}
%     \cs{regform}\marg{key=value list}
%   \end{syntax}
%   Stores speaker registration data.  Keys: |fullname|, |birthday|,
%   |position|, |phone|, |authoremail|, |confsection|, |copynum|,
%   |needliving|, |needinvitanion|.  Written to
%   \texttt{\textit{jobname}-regform.txt} when |\PaperLanguage| is
%   called.
% \end{function}
%
% \subsection{Body commands}
%
% \begin{function}{\PaperLanguage}
%   \begin{syntax}
%     \cs{PaperLanguage}\marg{language}
%   \end{syntax}
%   Selects \meta{language} (|ukrainian|, |russian|, or |english|),
%   calls |\maketitle|, and writes both the registration form and the
%   YAML article-info file.  This command should be the first thing
%   inside |\begin{document}|.
% \end{function}
%
% \begin{function}{\newlanguagecommand}
%   \begin{syntax}
%     \cs{newlanguagecommand}\marg{cmd}\marg{lang=text, \ldots}
%   \end{syntax}
%   Defines \meta{cmd} as a language-aware command.  Without an
%   optional argument it expands to the translation for the current
%   \pkg{babel} language; with |\meta{cmd}[|\meta{lang}|]| it uses
%   the specified language.  Missing translations produce the text
%   \texttt{UNSET TRANSLATION}.
% \end{function}
%
%^^A ===========================================================
% \section{Implementation}
%
% \iffalse
%<*package>
% \fi
%
%^^A -----------------------------------------------------------
% \subsection{Declaration}
%^^A -----------------------------------------------------------
%
% We require a recent kernel and load as an \pkg{expl3} class.
%    \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}[2022-06-01]
\ProvidesFile{iptconf.cls}[2026/05/24 v1.0 IPT conference class]
\ProvidesExplClass{iptconf}{2026-05-24}{1.0}
  {IPT conference class (Institute of Physics and Technology, KPI)}
\LoadClass[twocolumn, oneside]{article}[2022-06-01]
%    \end{macrocode}
%
%^^A -----------------------------------------------------------
% \subsection{Class options}
%^^A -----------------------------------------------------------
%
% Options are declared with \pkg{l3keys}.
% \begin{macro}{incollection,single}
%    \begin{macrocode}
\DeclareKeys [ iptconf ]
{
  incollection .code:n = \pagestyle{empty},
  single .code:n =
    {
      \pagestyle{plain}
      \setcounter{page}{#1}
    },
  single .default:n = 1,
}
\SetKeys    [ iptconf ] { incollection }
\ProcessKeyOptions [iptconf]
%    \end{macrocode}
% \end{macro}
%
%^^A -----------------------------------------------------------
% \subsection{Page geometry}
%^^A -----------------------------------------------------------
%
%    \begin{macrocode}
\RequirePackage[%
  a4paper,
  footskip = 1cm,
  headsep  = 0.3cm,
  top      = 2cm,
  bottom   = 2cm,
  left     = 2cm,
  right    = 2cm,
]{geometry}
%    \end{macrocode}
%
% Ensure the first paragraph of every section is indented
% (overrides the \cls{article} class default).
%    \begin{macrocode}
\let\@afterindentfalse\@afterindenttrue

\RequirePackage{xcolor}
%    \end{macrocode}
%
%^^A -----------------------------------------------------------
% \subsection{Fonts and language}
%^^A -----------------------------------------------------------
%
% We branch on the engine: \hologo{LuaLaTeX}/\hologo{XeLaTeX}
% use \pkg{fontsetup} for OpenType fonts; \hologo{pdfLaTeX}
% falls back to Type\,1 fonts with the OpenSans sans-serif family.
%
%    \begin{macrocode}
\bool_lazy_or:nnTF
  { \sys_if_engine_luatex_p: }
  { \sys_if_engine_xetex_p:  }
  {
    \RequirePackage{mathtools}
    \RequirePackage[default]{fontsetup}
    \RequirePackage
      [protrusion=true, tracking=true, babel=true]
      {microtype}
  }
  {
    \RequirePackage[T2A,T1]{fontenc}
    \RequirePackage{cmap}
    \renewcommand\sfdefault{opensans-LF}
    \renewcommand\bfdefault{b}
    \RequirePackage
      [protrusion=true, expansion, tracking=true,
       kerning=true, spacing=true, babel=true]
      {microtype}
    \RequirePackage{mathtools}
    \RequirePackage{amssymb}
  }

\RequirePackage{csquotes}
\RequirePackage[english, russian, ukrainian]{babel}
%    \end{macrocode}
%
% Make |\boldmath| active inside |\bfseries| so that bold text in
% titles automatically uses bold math symbols.
%    \begin{macrocode}
\g@addto@macro\bfseries{\boldmath}
%    \end{macrocode}
%
%^^A -----------------------------------------------------------
% \subsection{Language-aware commands}
%^^A -----------------------------------------------------------
%
% \begin{macro}{\newlanguagecommand}
%   Defines a new command \meta{cmd} that selects its output text
%   based on the current \pkg{babel} language (or an optional
%   language override).  Translations are stored in a \pkg{l3prop}
%   named |g_iptconf_nlc_|\meta{csname}|_prop|.
%    \begin{macrocode}
\NewDocumentCommand{\newlanguagecommand}{mm}
{
  \prop_new:c { \__iptconf_nlc_strip:N #1 }
  \prop_gset_from_keyval:cn { \__iptconf_nlc_strip:N #1 } { #2 }
  \NewDocumentCommand{#1}{o}
  {
    \IfNoValueTF { ##1 }
      { \iptconf_nlc:NV #1 \languagename }
      { \iptconf_nlc:Nn #1 { ##1 } }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\iptconf_nlc:Nn,\iptconf_nlc:NV}
%   Internal helper: given a command \meta{N} and a language name
%   \meta{n}, fetch the translation from the prop.
%    \begin{macrocode}
\cs_new:Nn \iptconf_nlc:Nn
{
  \prop_if_in:cnTF { \__iptconf_nlc_strip:N #1 } { #2 }
    { \prop_item:cn { \__iptconf_nlc_strip:N #1 } { #2 } }
    { UNSET ~ TRANSLATION }
}
\cs_generate_variant:Nn \iptconf_nlc:Nn { NV }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\__iptconf_nlc_strip:N}
%   Builds the prop name from a command name.
%    \begin{macrocode}
\cs_new:Nn \__iptconf_nlc_strip:N
  { g_iptconf_nlc_ \cs_to_str:N #1 _prop }
%    \end{macrocode}
% \end{macro}
%
%^^A -----------------------------------------------------------
% \subsubsection{Built-in language-aware strings}
%^^A -----------------------------------------------------------
%
% \begin{macro}{\iptbibname}
%    \begin{macrocode}
\newlanguagecommand{\iptbibname}{
  ukrainian = {Перелік ~ використаних ~ джерел},
  russian   = {Перечень ~ использованных ~ источников},
  english   = {References}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\keyname}
%    \begin{macrocode}
\newlanguagecommand{\keyname}{
  ukrainian = {Ключові ~ слова},
  russian   = {Ключевые ~ слова},
  english   = {Keywords}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\pacsnum}
%    \begin{macrocode}
\newlanguagecommand{\pacsnum}{
  ukrainian = {PACS ~ номери},
  russian   = {PACS ~ номера},
  english   = {PACS ~ numbers}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\udcnum}
%    \begin{macrocode}
\newlanguagecommand{\udcnum}{
  ukrainian = {УДК},
  russian   = {УДК},
  english   = {UDC}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ipt}
%   Expands to the full name of the institute in the current language.
%   Use this token inside |\affiliation| to obtain consistent output
%   and automatic abbreviation in YAML export.
%    \begin{macrocode}
\newlanguagecommand{\ipt}{
  ukrainian = {Навчально-науковий ~ Фізико-технічний ~ інститут},
  russian   = {Учебно-научный ~ Физико-технический ~ институт},
  english   = {Institute ~ of ~ Physics ~ and ~ Technology}
}
%    \end{macrocode}
% \end{macro}
%
%^^A -----------------------------------------------------------
% \subsection{\cs{PaperLanguage}}
%^^A -----------------------------------------------------------
%
% \begin{macro}{\PaperLanguage}
%   Selects the document language, typesets the title block, and
%   writes both metadata output files.
%    \begin{macrocode}
\NewDocumentCommand{ \PaperLanguage }{ m }
{
  \selectlanguage{#1}
  \maketitle
  \writeformdata
  \writearticleinfo
}
%    \end{macrocode}
% \end{macro}
%
%^^A -----------------------------------------------------------
% \subsection{Bibliography}
%^^A -----------------------------------------------------------
%
%    \begin{macrocode}
\RequirePackage[
  backend      = biber,
  bibstyle     = gost-numeric,
  sorting      = none,
  maxnames     = 10,
  autolang     = other,
  isbn         = true,
  url          = true,
  doi          = true,
  defernumbers = true,
]{biblatex}

\setcounter{biburllcpenalty}{100}
\setcounter{biburlucpenalty}{200}
\setcounter{biburlnumpenalty}{100}
%    \end{macrocode}
%
% Fine-tune bibliography spacing and penalties.
%    \begin{macrocode}
\setlength\bibitemsep{0.5\itemsep}
\setlength\biblabelsep{1ex}
\appto{\bibsetup}{%
  \clubpenalty\z@
  \widowpenalty\z@
  \interlinepenalty\z@
}
%    \end{macrocode}
%
% Automatically print the bibliography at |\end{document}|, using
% a language-sensitive heading.
%    \begin{macrocode}
\AddToHook{enddocument}[my]{%
  \ExplSyntaxOn
  \tl_set:Nx \l__ipt_bibname_tl
    { \iptconf_nlc:NV \iptbibname \languagename }
  \ExplSyntaxOff
  \printbibliography[ title = {\l__ipt_bibname_tl} ]
}
%    \end{macrocode}
%
%^^A -----------------------------------------------------------
% \subsection{Lists}
%^^A -----------------------------------------------------------
%
%    \begin{macrocode}
\RequirePackage{enumitem}
\setlist{nosep}
%    \end{macrocode}
%
%^^A -----------------------------------------------------------
% \subsection{Balanced columns}
%^^A -----------------------------------------------------------
%
% \pkg{flushend} balances the two columns on the final page.
%    \begin{macrocode}
\RequirePackage{flushend}

\def\initialize@flushend{%
  \global\let\saved@orig@@outputdblcol\@outputdblcol
  \global\let\balanced@@outputdblcol\last@outputdblcol
  \AddToHook{enddocument}[flushend]
    { \let\@outputdblcol\balanced@@outputdblcol }%
  \g@addto@macro\footnoterule{ \vskip\z@ }%
  \savingvdiscards=\@ne
}
%    \end{macrocode}
%
%^^A -----------------------------------------------------------
% \subsection{Speaker registration form}
%^^A -----------------------------------------------------------
%
% Keys for the |\regform| command.
%    \begin{macrocode}
\keys_define:nn { iptconf }
{
  fullname       .str_set:N = \l_iptconf_fullname_str,
  birthday       .str_set:N = \l_iptconf_birthday_str,
  position       .str_set:N = \l_iptconf_position_str,
  phone          .str_set:N = \l_iptconf_phone_str,
  authoremail    .str_set:N = \l_iptconf_authoremail_str,
  confsection    .str_set:N = \l_iptconf_confsection_str,
  copynum        .str_set:N = \l_iptconf_copynum_str,
  needliving     .str_set:N = \l_iptconf_needliving_str,
  needinvitanion .str_set:N = \l_iptconf_needinvitanion_str,
}
%    \end{macrocode}
%
% \begin{macro}{\regform}
%    \begin{macrocode}
\DeclareDocumentCommand \regform { m }
{
  \keys_set:nn { iptconf } { #1 }
}
%    \end{macrocode}
% \end{macro}
%
%^^A -----------------------------------------------------------
% \subsection{Title machinery}
%^^A -----------------------------------------------------------
%
% \subsubsection{Variable declarations}
%
% Token list variables for single-valued metadata.
%    \begin{macrocode}
\tl_new:N \l_iptconf_udc_tl
\tl_new:N \l_iptconf_pacs_tl
\tl_new:N \l_iptconf_abstract_tl
\tl_new:N \l_iptconf_keywords_tl
\tl_new:N \l_iptconf_author_tl
\tl_new:N \l_iptconf_author_email_tl
\tl_new:N \l_iptconf_author_affiliation_tl
\tl_new:N \l_iptconf_title_tl
\tl_new:N \l_iptconf_affiliation_tl
\tl_new:N \l_iptconf_affiliation_number_tl
%    \end{macrocode}
%
% Sequence variables for multi-valued data.
%    \begin{macrocode}
\seq_new:N \g_iptconf_authors_seq
\seq_new:N \g_iptconf_justauthors_seq
\seq_new:N \g_iptconf_affiliation_seq
\seq_new:N \g_iptconf_justaffiliation_seq
%    \end{macrocode}
%
% IO stream for the \texttt{.dat} auxiliary file.
%    \begin{macrocode}
\iow_new:N \g_iptconf_totoc_iow
\iow_open:Nn \g_iptconf_totoc_iow { \c_sys_jobname_str .dat }
%    \end{macrocode}
%
% \subsubsection{Preamble metadata commands}
%
% \begin{macro}{\title}
%    \begin{macrocode}
\RenewDocumentCommand{\title}{ m }
{
  \tl_set:Nn \l_iptconf_title_tl {#1}
  \iow_now:Nx \g_iptconf_totoc_iow
  {
    \iow_char:N \\thispapertitle
    \iow_char:N \{
    \exp_not:n {#1}
    \iow_char:N \}
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\author}
%    \begin{macrocode}
\RenewDocumentCommand{\author}{ O{} m m }
{
  \tl_set:Nn \l_iptconf_author_tl           {#2}
  \tl_set:Nn \l_iptconf_author_email_tl     {#1}
  \tl_set:Nn \l_iptconf_author_affiliation_tl {#3}
  \seq_gput_right:Nn \g_iptconf_justauthors_seq {#2}
  \seq_gput_right:Nn \g_iptconf_authors_seq
  {
    #2\textsuperscript{#3}
    \tl_if_empty:nTF {#1}
      { }
      { \textsuperscript{,}\thanks{#1} }
  }
  \iow_now:Nx \g_iptconf_totoc_iow
  {
    \iow_char:N \\thispaperauthor
    \iow_char:N \{
    \exp_not:n {#2}
    \iow_char:N \}
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\affiliation}
%    \begin{macrocode}
\NewDocumentCommand{\affiliation}{m m}
{
  \tl_set:Nn \l_iptconf_affiliation_tl        {#1}
  \tl_set:Nn \l_iptconf_affiliation_number_tl {#2}
  \seq_gput_right:Nn \g_iptconf_affiliation_seq
    { \textsuperscript{#2}\ #1 }
  \seq_gput_right:Nn \g_iptconf_justaffiliation_seq {#1}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@affiliation}
%   Typesets the affiliation list with |\\[2ex]| separators.
%    \begin{macrocode}
\NewDocumentCommand{\@affiliation}{ }
{
  \seq_use:Nnnn
    \g_iptconf_affiliation_seq
    {\\[2ex]} {\\[2ex]} {\\[2ex]}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\udc}
%    \begin{macrocode}
\NewDocumentCommand\udc{ m }
{
  \tl_set:Nn \l_iptconf_udc_tl {#1}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\pacs}
%    \begin{macrocode}
\NewDocumentCommand\pacs{ m }
{
  \tl_set:Nn \l_iptconf_pacs_tl {#1}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\keywords}
%    \begin{macrocode}
\NewDocumentCommand\keywords{m}
{
  \tl_set:Nn \l_iptconf_keywords_tl { #1 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\abstract}
%    \begin{macrocode}
\RenewDocumentCommand\abstract{ +m }
{
  \tl_set:Nn \l_iptconf_abstract_tl {#1}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@abstract}
%    \begin{macrocode}
\NewDocumentCommand\@abstract{ }
{
  \tl_use:N \l_iptconf_abstract_tl
}
%    \end{macrocode}
% \end{macro}
%
% Suppress the automatic date in the title.
%    \begin{macrocode}
\date{}
%    \end{macrocode}
%
% \subsubsection{Auxiliary author sequence}
%
% \begin{macro}{\authors}
%   Outputs the comma-separated list of authors with affiliation
%   superscripts and optional e-mail footnotes.
%    \begin{macrocode}
\NewDocumentCommand\authors{ }
{
  \seq_use:Nnnn \g_iptconf_authors_seq {,~} {,~} {,~}
}
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{The title block}
%
% \begin{macro}[int]{\@maketitle}
%    \begin{macrocode}
\RenewDocumentCommand\@maketitle{ }
{
  \newpage
  \tl_if_empty:NTF \l_iptconf_pacs_tl
    { }
    { \pacsnum\ \tl_use:N \l_iptconf_pacs_tl }
  \tl_if_empty:NTF \l_iptconf_udc_tl
    { }
    { \udcnum\ \tl_use:N \l_iptconf_udc_tl }
  \nopagebreak
  \null
  \vskip 1em
  \begin{center}
    \let\footnote\thanks
    {\Large\bfseries\sffamily
      \text_uppercase:n { \tl_use:N \l_iptconf_title_tl } \par
    }
    \vskip 1.5em
    {\large
      \lineskip .5em
      \begin{center}
        \authors
      \end{center}
      \par
    }
    \vskip 1ex
    {\@affiliation}
  \end{center}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\maketitle}
%   Sets the footnote counter format (Cyrillic letters for Slavic
%   languages, Latin letters for English), then dispatches to the
%   appropriate one- or two-column layout.
%    \begin{macrocode}
\renewcommand\maketitle{\par
  \begingroup
  \iflanguage{ukrainian}%
    {\renewcommand\thefootnote{\itshape\asbuk{footnote}}}%
    {%
      \iflanguage{russian}%
        {\renewcommand\thefootnote{\itshape\asbuk{footnote}}}%
        {%
          \iflanguage{english}
            {\renewcommand\thefootnote{\itshape\alph{footnote}}}%
            {}%
        }%
    }%
  \if@twocolumn
    \ifnum \col@number=\@ne
      \@maketitle
      \noindent\hrulefill\par
      \vspace{1.3ex}
      {\large\bfseries \abstractname}
      \begingroup
        \quotation
        \@abstract
        \endquotation
      \endgroup
      \noindent{\bfseries \keyname}:~\tl_use:N \l_iptconf_keywords_tl \par
      \smallskip\noindent\hrulefill\medskip
    \else
      \twocolumn[\@maketitle
        \noindent\hrulefill\par
        \vspace{1.3ex}
        {\large\bfseries \abstractname}
        \begingroup
          \quotation
          \@abstract
          \endquotation
        \endgroup
        \vskip 1em
        \noindent{\bfseries \keyname}:~\tl_use:N \l_iptconf_keywords_tl \par
        \smallskip\noindent\hrulefill\bigskip
      ]%
    \fi
  \else
    \newpage
    \global\@topnum\z@
    \@maketitle
  \fi
  \@thanks
  \endgroup
  \setcounter{footnote}{0}%
  \global\let\thanks\relax
  \global\let\maketitle\relax
  \global\let\@maketitle\relax
  \global\let\@thanks\@empty
  \global\let\@author\@empty
  \global\let\@date\@empty
  \global\let\@title\@empty
  \global\let\title\relax
  \global\let\author\relax
  \global\let\date\relax
  \global\let\and\relax
}
%    \end{macrocode}
% \end{macro}
%
% Write |\finishauthors| and close the stream at |\end{document}|.
%    \begin{macrocode}
\AtEndDocument
{
  \iow_now:Nx \g_iptconf_totoc_iow { \iow_char:N \\finishauthors }
  \iow_close:N \g_iptconf_totoc_iow
}
%    \end{macrocode}
%
%^^A -----------------------------------------------------------
% \subsection{Section headings}
%^^A -----------------------------------------------------------
%
% \begin{macro}[int]{\iptconf_seccntformat:n}
%   Adds a period after the section number.
%    \begin{macrocode}
\cs_gset_protected:Npn \iptconf_seccntformat:n #1
{
  \csname the#1\endcsname.\enskip
}
\cs_gset_eq:NN \@seccntformat \iptconf_seccntformat:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\section}
%    \begin{macrocode}
\cs_gset_protected:Npn \iptconf_section:
{
  \@startsection {section}{1}{\z@}%
    {-2ex \@plus -1ex \@minus -.2ex}%
    {1.3ex \@plus .2ex}%
    {\normalfont\large\bfseries\raggedright}
}

\cs_new_protected:Npn \iptconf_section_star:n #1
{
  \iptconf_section:*{#1}
  \addcontentsline{toc}{section}{#1}
}

\RenewDocumentCommand \section {s o m}
{
  \IfBooleanTF{#1}
    { \iptconf_section_star:n {#3} }
    {
      \IfNoValueTF{#2}
        { \iptconf_section: {#3} }
        { \iptconf_section: [#2]{#3} }
    }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\subsection}
%    \begin{macrocode}
\cs_gset_protected:Npn \iptconf_subsection:
{
  \@startsection{subsection}{2}{\z@}%
    {-3.25ex \@plus -1ex \@minus -.2ex}%
    {1.5ex \@plus .2ex}%
    {\normalfont\bfseries\raggedright}
}

\cs_new_protected:Npn \iptconf_subsection_star:n #1
{
  \iptconf_subsection:*{#1}
  \addcontentsline{toc}{subsection}{#1}
}

\RenewDocumentCommand \subsection {s o m}
{
  \IfBooleanTF{#1}
    { \iptconf_subsection_star:n {#3} }
    {
      \IfNoValueTF{#2}
        { \iptconf_subsection: {#3} }
        { \iptconf_subsection: [#2]{#3} }
    }
}
%    \end{macrocode}
% \end{macro}
%
%^^A -----------------------------------------------------------
% \subsection{Figures and tables}
%^^A -----------------------------------------------------------
%
%    \begin{macrocode}
\RequirePackage[labelformat=simple]{subcaption}
\RequirePackage[labelsep=period]{caption}
%    \end{macrocode}
%
% \begin{macro}{\figcaption,\tabcaption}
%   Allow |\figcaption| and |\tabcaption| outside a float, as is
%   common in double-column layouts where floats span the column.
%    \begin{macrocode}
\def\tabcaption{\def\@captype{table}\caption}
\def\figcaption{\def\@captype{figure}\caption}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\renewcommand\thesubfigure{(\alph{subfigure})}
\captionsetup[subfigure]{justification=centering, subrefformat=parens}
%    \end{macrocode}
%
%^^A -----------------------------------------------------------
% \subsection{Hyperlinks}
%^^A -----------------------------------------------------------
%
%    \begin{macrocode}
\RequirePackage[
  colorlinks      = true,
  urlcolor        = blue,
  linkcolor       = red!60!black,
  citecolor       = green!50!black,
  bookmarks,
  bookmarksnumbered = true,
  breaklinks      = true,
  unicode,
  linktoc         = all,
  hypertexnames   = false,
]{hyperref}
%    \end{macrocode}
%
%^^A -----------------------------------------------------------
% \subsection{Metadata output}
%^^A -----------------------------------------------------------
%
% \begin{macro}[int]{\g_iptconf_regform_iow}
%    \begin{macrocode}
\iow_new:N \g_iptconf_regform_iow
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\writeformdata}
%   Writes the speaker registration form to
%   \texttt{\textit{jobname}-regform.txt}.
%    \begin{macrocode}
\NewDocumentCommand \writeformdata {} {
  \iow_open:Nn \g_iptconf_regform_iow
    { \c_sys_jobname_str -regform.txt }
  \iow_now:Nx \g_iptconf_regform_iow
  {
    \text_expand:n
      { Повне ~ ім'я ~ доповідача: ~ \str_use:N \l_iptconf_fullname_str }
    \iow_newline:
    \text_expand:n
      { Дата ~ народження: ~ \str_use:N \l_iptconf_birthday_str }
    \iow_newline:
    \text_expand:n
      { Посада ~ доповідача: ~ \str_use:N \l_iptconf_position_str }
    \iow_newline:
    \text_expand:n
      { Телефонний ~ номер: ~ \str_use:N \l_iptconf_phone_str }
    \iow_newline:
    \text_expand:n
      { Email: ~ \str_use:N \l_iptconf_authoremail_str }
    \iow_newline:
    \text_expand:n
      { Секція: ~ \str_use:N \l_iptconf_confsection_str }
    \iow_newline:
    \text_expand:n
      { Кількість ~ копій: ~ \str_use:N \l_iptconf_copynum_str }
    \iow_newline:
    \text_expand:n
      { Потреба ~ в ~ житлі: ~ \str_use:N \l_iptconf_needliving_str }
    \iow_newline:
    \text_expand:n
      { Потреба ~ в ~ запрошенні: ~
        \str_use:N \l_iptconf_needinvitanion_str }
    \iow_newline:
  }
  \iow_close:N \g_iptconf_regform_iow
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\writearticleinfo}
%   Writes structured YAML article metadata to
%   \texttt{\textit{jobname}-info.yaml}.  Mathematical macros and
%   special tokens are purified before output.
%    \begin{macrocode}
\NewDocumentCommand \writearticleinfo {} {

  \text_declare_purify_equivalent:Nn \LaTeX  { LaTeX }
  \text_declare_purify_equivalent:Nn \TeX    { TeX }
  \text_declare_purify_equivalent:Nn \LaTeXe { LaTeX2e }

  % Remove trailing period from keywords, then split into clist
  \regex_replace_once:nnN { \.\s*\z } {} \l_iptconf_keywords_tl
  \clist_set:Nx \l_iptconf_keywords_clist
    { \tl_use:N \l_iptconf_keywords_tl }

  % Register Greek letter macros as their ASCII names for purification
  \clist_map_inline:nn
  {
    alpha, beta, gamma, delta, epsilon, zeta, eta, theta,
    iota, kappa, lambda, mu, nu, xi, omicron, pi, rho,
    sigma, tau, upsilon, phi, chi, psi, omega,
    Gamma, Delta, Theta, Lambda, Xi, Pi, Sigma, Upsilon, Phi, Psi, Omega
  }
  {
    \exp_args:Ne \text_declare_purify_equivalent:Nn
      { \cs:w ##1 \cs_end: } { ##1 }
  }

  % Clean author names: replace ~ with regular space
  \seq_clear_new:N \g_cleanauthors_seq
  \seq_map_inline:Nn \g_iptconf_justauthors_seq
  {
    \tl_set:Nn \l_tmpa_tl { ##1 }
    \regex_replace_all:nnN { [\~] } { \  } \l_tmpa_tl
    \seq_put_right:NV \g_cleanauthors_seq \l_tmpa_tl
  }

  % Purify title and abstract
  \tl_set_eq:NN \l_cleanabstract_tl \l_iptconf_abstract_tl
  \regex_replace_all:nnN { [\$] } { } \l_cleanabstract_tl
  \tl_set_eq:NN \l_cleantitle_tl \l_iptconf_title_tl
  \regex_replace_all:nnN { [\$] } { } \l_cleantitle_tl

  \iow_open:Nn \g_iptconf_regform_iow
    { \c_sys_jobname_str -info.yaml }

  \iow_now:Nx \g_iptconf_regform_iow
    { title: ~ " \text_purify:n { \l_cleantitle_tl } " }
  \iow_now:Nx \g_iptconf_regform_iow
    { speaker: ~ " \str_use:N \l_iptconf_fullname_str " }
  \iow_now:Nx \g_iptconf_regform_iow
    { section: ~ " \str_use:N \l_iptconf_confsection_str " }

  \iow_now:Nn \g_iptconf_regform_iow { authors: }
  \seq_map_inline:Nn \g_cleanauthors_seq
  {
    \iow_now:Nx \g_iptconf_regform_iow
      { ~ - ~ " \text_purify:n {##1} " }
  }

  \iow_now:Nn \g_iptconf_regform_iow { affiliations: }
  \seq_map_inline:Nn \g_iptconf_justaffiliation_seq
  {
    \str_if_eq:nnTF {##1} {\ipt}
      { \iow_now:Nn \g_iptconf_regform_iow { ~ - ~ "НН ~ ФТІ" } }
      {
        \iow_now:Nx \g_iptconf_regform_iow
          { ~ - ~ " \text_purify:n {##1} " }
      }
  }

  \iow_now:Nx \g_iptconf_regform_iow { abstract: ~ > }
  \iow_now:Nx \g_iptconf_regform_iow
    { ~ " \text_purify:n { \l_cleanabstract_tl } " }

  \iow_now:Nn \g_iptconf_regform_iow { keywords: }
  \clist_map_inline:Nn \l_iptconf_keywords_clist
  {
    \iow_now:Nn \g_iptconf_regform_iow { ~ - ~ "##1" }
  }

  \iow_close:N \g_iptconf_regform_iow
}
%    \end{macrocode}
% \end{macro}
%
% \iffalse
%</package>
% \fi
%
% \Finale
\endinput
