%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% File jslectureplanner.sty
%%
%% Package to manage university courses.
%%
%% This file is part of the jslectureplanner bundle.
%%
%% Author: Juergen Spitzmueller <juergen.spitzmueller@univie.ac.at>
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%%   http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2003/12/01 or later.
%%
%% This work has the LPPL maintenance status "maintained".
%% 
%% The Current Maintainer of this work is Juergen Spitzmueller.
%%
%% Code repository and issue tracker: https://github.com/jspitz/jslectureplanner
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\def\filedate{2024/03/06}
\def\fileversion{1.13}
\def\filename{jslectureplanner.sty}

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{jslectureplanner}
	[\filedate\space v\fileversion\space JS lecture planner]


%
% REQUIRED PACKAGES
%
\RequirePackage{etoolbox}
\RequirePackage[calc,useregional]{datetime2}
\RequirePackage{calc}
\RequirePackage{ifthen}


%
% VARIABLES
%
\def\lectype{}
\def\lectypeverb{}
\def\lectypesession{}
\def\lectitle{}
\def\lectitlesep{}
\def\lecsubtitle{}
\def\lecshorttitle{}
\def\lecsemshort{}
\def\lecnsemshort{}
\def\lecsemverb{}
\def\lecnsemverb{}
\def\lecnsemny{}
\def\lecyear{}
\def\lecendyear{}
\def\lecendyearsep{/}
\def\lecsemester{}
\def\lecsemesterverb{}
\def\lecuniversity{}
\def\lecinstitute{}
\def\lecroom{}
\def\lecstartdate{}
\def\lecstarttime{}
\def\@lecstarttime{}
\def\lecduration{90}
\def\lecinstructor{}
\def\lecshortinstructor{}

\def\lecplatform{}
\def\officenumber{}
\def\officehours{}

\def\sesdate{}
\def\sesshortdate{}
\def\sesdtmdate{}
\def\sesstarttime{}
\def\sestitle{}
\def\sesshorttitle{}
\def\sestitlesep{}
\def\sessubtitle{}
\def\sesnr{}

\def\programlist{}
\def\programlistexam{}
\def\programlistbeamer{}
\def\programlistbeamerexam{}
\def\programblocklistbeamer{}
\def\jsbiblist{}


%
% COUNTERS
%
\newcounter{sesunit}
\newcounter{dateratio}
\setcounter{dateratio}{1}
\newcounter{cancellations}
\newcounter{snum}
\newcounter{blocks}
\newcounter{fbreaks}
\newcounter{lecinterval}
\setcounter{lecinterval}{7}
\newcounter{sesoffset}
\newcounter{autooffset}
\newcounter{autooffsettrigger}
\newcounter{autooffsetcounter}
\newcounter{breakunits}
\newcounter{loopcounter}
\newcounter{adjsession}
\newcounter{sestopic}
\newcounter{exams}


%
% STRINGS
%

% 1) Course types
%
% vl
\def\lectypeverb@vl{Vorlesung}
\def\lectype@vl{VL}
\def\lectypesession@vl{Vorlesung}
% vo (redundant and undocumented;
%     just kept for historical reasons)
\def\lectypeverb@vo{Vorlesung}
\def\lectype@vo{VO}
\def\lectypesession@vo{Vorlesung}
% ps
\def\lectypeverb@ps{Proseminar}
\def\lectype@ps{PS}
\def\lectypesession@ps{Sitzung}
% se
\def\lectypeverb@se{Seminar}
\def\lectype@se{SE}
\def\lectypesession@se{Sitzung}
% ue
\def\lectypeverb@ue{\"Ubung}
\def\lectype@ue{UE}
\def\lectypesession@ue{Sitzung}
% ko
\def\lectypeverb@ko{Kolloquium}
\def\lectype@ko{KO}
\def\lectypesession@ko{Sitzung}
% pv
\def\lectypeverb@pv{Privatissimum}
\def\lectype@pv{PV}
\def\lectypesession@pv{Sitzung}

% 2.) Term types
%
% fs
\def\lecsemverb@fs{Fr\"uhjahrssemester}
\def\lecsemshort@fs{FS}
\def\lecsemnext@fs{hs}
\def\lecsemnextny@fs{n}
% hs
\def\lecsemverb@hs{Herbstsemester}
\def\lecsemshort@hs{HS}
\def\lecsemnext@hs{fs}
\def\lecsemnextny@hs{y}
% ss
\def\lecsemverb@ss{Sommersemester}
\def\lecsemshort@ss{SoSe}
\def\lecsemnext@ss{ws}
\def\lecsemnextny@ss{n}
% ws
\def\lecsemverb@ws{Wintersemester}
\def\lecsemshort@ws{WS}
\def\lecsemnext@ws{ss}
\def\lecsemnextny@ws{y}


% 3.) misc.
%
% Suffix to cancelled sessions
\newcommand*\leccancel{\ -- keine \lectypesession}
% Beamer program heading
\newcommand*\lecprogram{Programm}
% Program list indentation
\newcommand*\lecprogramlistindent{\programdateformat{88.\,88.}}
% Session topic placeholder
\newcommand*\sestopic{Thema~\thesestopic}
% Time slot
\newcommand*\jstimeslot[2]{#1\,--\,#2}


%
% Booleans
%
\newtoggle{uniquelecshortinstructor}
\newtoggle{uniquesesinstructor}
\newtoggle{uniquesesshortinstructor}
\newtoggle{uniquelecshorttitle}
\newtoggle{uniquesesshorttitle}

%
% HELPERS
%

% Helper command that uses etoolbox's \AtEndPreamble iff
% we actually are in a preamble. If not, the argument is
% output as is.
\newcommand\js@AtEndPreambleIfInPreamble[1]{%
  \ifx\@onlypreamble\@notprerr
   #1
  \else
   \AtEndPreamble{#1}
  \fi
}

%
% PACKAGE OPTIONS
%

\DeclareKeys[lec]
{
  % type=<type>
  type.code = {
    \js@AtEndPreambleIfInPreamble{%
      \ifcsundef{lectype@#1}{%
         \PackageError{jslectureplanner}{Lecture type '#1' is not defined!}{%
	       Please consult the package manual for instructions how to define it}
      }{}
      \def\lectype{\csuse{lectype@#1}}%
      \def\lectypeverb{\csuse{lectypeverb@#1}}%
      \def\lectypesession{\csuse{lectypesession@#1}}%
    }%
  },
  % semester=<type>
  semester.code = {
    \js@AtEndPreambleIfInPreamble{%
      \ifcsundef{lecsemshort@#1}{%
         \PackageError{jslectureplanner}{Semester type '#1' is not defined!}{%
	       Please consult the package manual for instructions how to define it}
      }{}
      \def\lecsemshort{\csuse{lecsemshort@#1}}%
      \def\lecsemverb{\csuse{lecsemverb@#1}}%
      \def\@nextsem{\csuse{lecsemnext@#1}}%
      \def\lecnsemshort{\csuse{lecsemshort@\@nextsem}}%
      \def\lecnsemverb{\csuse{lecsemverb@\@nextsem}}%
      \def\lecnsemny{\csuse{lecsemnextny@#1}}%
    }%
  },
  % title=<title>
  title.code = {
    \def\lectitle{#1}%
    \ifx\lecshorttitle\empty%
      \def\lecshorttitle{#1}%
      \global\togglefalse{uniquelecshorttitle}%
    \fi
  },
  % titlesep=<sep>
  titlesep.store = \lectitlesep,
  % subtitle=<sep>
  subtitle.store = \lecsubtitle,
  % shorttitle=<title>
  shorttitle.code = {
    \def\lecshorttitle{#1}
    \global\toggletrue{uniquelecshorttitle}
  },
  % year=<year>
  year.store = \lecyear,
  % endyear=<year>
  endyear.store = \lecendyear,
  % uni=<university>
  uni.store = \lecuniversity,
  % institute=<institute>
  institute.store = \lecinstitute,
  % platform=<platform>
  platform.store = \lecplatform,
  % officehours=<officehours>
  officehours.store = \lecofficehours,
  % officenumber=<officenumber>
  officenumber.store = \lecofficenumber,
  % room=<room>
  room.store = \lecroom,
  % startdate=<startdate>
  startdate.store = \lecstartdate,
  % starttime=<starttime>
  starttime.code = {
    \def\@lecstarttime{#1}
    \def\lecstarttime{\DTMtime{#1}}
  },
  % duration=<duration>
  duration.store = \lecduration,
  % instructor=<instructor>
  instructor.code = {
    \def\lecinstructor{#1}%
    \ifx\lecshortinstructor\empty
      \def\lecshortinstructor{#1}
    \fi
  },
  % shortinstructor=<shortinstructor>
  shortinstructor.code = {
    \def\lecshortinstructor{#1}%
    \global\toggletrue{uniquelecshortinstructor}
  },
  % style=<style>
  style.code = {
    \AtEndOfPackage{\input{#1.lps}}
  },
  % interval=<interval>
  interval.code = {
    % test if the input is a number
    % courtesy of egreg at http://tex.stackexchange.com/a/50131
    \if\relax\detokenize\expandafter{\romannumeral-0#1}\relax
      \setcounter{lecinterval}{#1}%
    \else
      \PackageError{jslectureplanner}{%
        Value of 'interval' option must be a number\MessageBreak
        ('#1' was given instead)}{}%
    \fi
  },
  % sestitlesep=<sestitlesep>
  sestitlesep.store = \sestitlesep
}

% Process package options
\ProcessKeyOptions[lec]

%
% End Options
%%


%
% ALTERNATIVE SETUP MACROS
%
\RequirePackage{xparse}

% LecYear parses and splits {...}{startyear/endyear}
\ExplSyntaxOn
\NewDocumentCommand \LecYear { m m }
{
   % #1: semester/term
   \SetKeys[lec]{semester=#1}
   % split #2 at / if available (startyear/endyear)
   \seq_set_split:Nnn \seq_jslp_lec_year { / } { #2 }
   \seq_pop_left:NNT \seq_jslp_lec_year \tl_jslp_start_year
   { 
      \SetKeys[lec]{year=\tl_jslp_start_year} 
   }
   \seq_get_right:NNT \seq_jslp_lec_year \tl_jslp_end_year
   {
       \SetKeys[lec]{endyear=\tl_jslp_end_year}
   }
}
\ExplSyntaxOff

\newcommand*{\LecType}[1]{\SetKeys[lec]{type=#1}}
\newcommand*{\LecTitle}[2][]{\SetKeys[lec]{shorttitle={#2},#1,title={#2}}}
\newcommand*{\LecTitleSep}[1]{\SetKeys[lec]{titlesep={#1}}}
\newcommand*{\LecSubTitle}[1]{\SetKeys[lec]{subtitle={#1}}}
\newcommand*{\LecUni}[1]{\SetKeys[lec]{uni={#1}}}
\newcommand*{\LecInstitute}[1]{\SetKeys[lec]{institute={#1}}}
\newcommand*{\LecRoom}[1]{\SetKeys[lec]{room={#1}}}
\newcommand*{\LecStartDate}[1]{\SetKeys[lec]{startdate=#1}}
\newcommand*{\LecStartTime}[1]{\SetKeys[lec]{starttime=#1}}
\newcommand*{\LecDuration}[1]{\SetKeys[lec]{duration=#1}}
\newcommand*{\LecInstructor}[2][\empty]{%
    \ifx#1\empty
        \SetKeys[lec]{instructor={#2}}%
    \else
        \SetKeys[lec]{instructor={#2},shortinstructor={#1}}%
    \fi
}
\newcommand*{\LecInterval}[1]{\SetKeys[lec]{interval=#1}}
\newcommand*{\SessionTitleSep}[1]{\SetKeys[lec]{sestitlesep=#1}}


%
% END TIME CALCULATION
%
% Courtesy of Christian Hupfer at
% https://tex.stackexchange.com/a/473552/19291

\ExplSyntaxOn
\cs_generate_variant:Nn \int_set:Nn {NV}
\cs_generate_variant:Nn \seq_set_split:Nnn {NVn,NVV}

\NewDocumentCommand{\jslp@endtime}{+m+m}{%
	\group_begin:
	\tl_set:Nx \l_tmpa_tl {#1}
	\seq_set_split:NVV \l_tmpa_seq {\c_colon_str} \l_tmpa_tl
	\exp_args:NNx \fp_set:Nn \l_tmpa_fp {\seq_item:Nn \l_tmpa_seq {1} * 3600 + \seq_item:Nn \l_tmpa_seq {2} * 60 + \seq_item:Nn \l_tmpa_seq {3}  }
	\exp_args:NNx \fp_set:Nn \l_tmpb_fp {#2 * 60}
	\fp_add:Nn \l_tmpa_fp {#2 * 60} 
	\tl_clear:N \l_tmpa_tl 
	% Compute hours
	\exp_args:NNx \int_set:Nn \l_tmpa_int {\int_div_truncate:nn {\fp_use:N \l_tmpa_fp}{3600}}
	\int_compare:nNnTF {\l_tmpa_int } > {23} {% After midnight?
	  \exp_args:NNx \int_set:Nn \l_tmpb_int {\int_mod:nn {\l_tmpa_int } {24}}
	}{%
	  \int_set_eq:NN \l_tmpb_int \l_tmpa_int
	}
	\tl_put_right:NV \l_tmpa_tl {\l_tmpb_int\c_colon_str}

	% Remaining seconds, split them into minutes and seconds 
	\int_set:Nn \l_tmpa_int {\fp_use:N \l_tmpa_fp}

	\exp_args:NNx \int_set:Nn \l_tmpb_int {\int_mod:nn {\l_tmpa_int}{3600}}
	\exp_args:NNx \int_set:Nn \l_tmpb_int {\int_div_truncate:nn {\l_tmpb_int}{60}}
	\tl_put_right:NV \l_tmpa_tl {\l_tmpb_int\c_colon_str}
	% Finally splitting: Seconds
	\exp_args:NNx \int_set:Nn \l_tmpa_int {\int_mod:nn {\l_tmpa_int}{60}}
	\tl_put_right:NV \l_tmpa_tl {\l_tmpa_int}
	% Display output:
	\exp_args:NV \DTMtime{\l_tmpa_tl}
	\group_end:
}

\ExplSyntaxOff


%
% CONCATENATED VARIABLES
%
\def\lecsemester{\lecsemshort~\lecyear\ifcsempty{lecendyear}{}{\lecendyearsep\lecendyear}}
\def\lecsemesterverb{\lecsemverb\ \lecyear\ifcsempty{lecendyear}{}{\lecendyearsep\lecendyear}}
\def\lecfulltitle{\lectitle\lectitlesep\lecsubtitle}
\def\sesfulltitle{\sestitle\sestitlesep\sessubtitle}
\def\lecendtime{\jslp@endtime{\@lecstarttime}{\lecduration}}
\newcommand*\lecslot{\jstimeslot{\lecstarttime}{\lecendtime}}


%
% CUSTOM DATE FORMATS (via datetime2)
%

\DTMnewdatestyle{lecdate}{% long date: DD.\,MM.~YYYY
  \renewcommand*{\DTMdisplaydate}[4]{\DTMtwodigits{##3}.\,\DTMtwodigits{##2}.~##1}%
  \renewcommand*{\DTMDisplaydate}{\DTMdisplaydate}%
}

\DTMnewdatestyle{lecshortdate}{% short date: DD.\,MM.
  \renewcommand*{\DTMdisplaydate}[4]{\DTMtwodigits{##3}.\,\DTMtwodigits{##2}.}%
  \renewcommand*{\DTMDisplaydate}{\DTMdisplaydate}%
}


%
% CUSTOM TIME FORMATS (via datetime2)
%

\DTMsettimestyle{default}
\DTMsetup{showseconds=false}

% Simple test for substring. Courtesy of egreg at
% https://tex.stackexchange.com/a/26873/19291
\def\jslp@instring#1#2{TT\fi\begingroup
  \edef\x{\endgroup\noexpand\in@{#1}{#2}}\x\ifin@}

% Internal macro to set the date to a given value
% Code adapted from advdate.sty
\newcommand\jslp@SetDate[1][\s@v@dT@d@y]{\edef\d@t@{#1}%
\if\jslp@instring{-}{\d@t@}%
  \expandafter\iso@t@d@y\d@t@\iso@t@d@y%
\else%
  \expandafter\t@d@y\d@t@\t@d@y%
\fi}
\def\t@d@y#1/#2/#3\t@d@y{\day#1 \month#2 \year#3 \relax}
\def\iso@t@d@y#1-#2-#3\iso@t@d@y{\day#3 \month#2 \year#1 \relax}


%
% CUSTOMIZATION OF STRINGS
%

% 1) Course types
%
\newcommand*\DefLecType[4]{%
  \csdef{lectype@#1}{#2}
  \csdef{lectypeverb@#1}{#3}
  \csdef{lectypesession@#1}{#4}
}
%
% Kept for backwards compatibility
% vl
\newcommand*\DefTypeVL[3]{%
  \DefLecType{vl}{#1}{#2}{#3}
}
% vo (redundant and undocumented;
%     just kept for historical reasons)
\newcommand*\DefTypeVO[3]{%
  \DefLecType{vo}{#1}{#2}{#3}
}
% ps
\newcommand*\DefTypePS[3]{%
  \DefLecType{ps}{#1}{#2}{#3}
}
% se
\newcommand*\DefTypeSE[3]{%
  \DefLecType{se}{#1}{#2}{#3}
}
% ue
\newcommand*\DefTypeUE[3]{%
  \DefLecType{ue}{#1}{#2}{#3}
}
% ko
\newcommand*\DefTypeKO[3]{%
  \DefLecType{ko}{#1}{#2}{#3}
}
% pv
\newcommand*\DefTypePV[3]{%
  \DefLecType{pv}{#1}{#2}{#3}
}

% 2.) Term types
%
\newif\if@jslp@semtype@nextny\@jslp@semtype@nextnyfalse
\DeclareKeys[semtype]
{
	next.store = \@ltn,
	nextny.if = @jslp@semtype@nextny
}

\newcommand*\DefSemType[4][\empty]{%
  \csdef{@ltn}{}
  \csdef{lecsemshort@#2}{#3}
  \csdef{lecsemverb@#2}{#4}
  \ifx\empty#1\else%
        \SetKeys[semtype]{nextny=false}%
        \SetKeys[semtype]{#1}%
        \if@jslp@semtype@nextny
            \csdef{lecsemnextny@#2}{y}
        \else
            \csdef{lecsemnextny@#2}{n}
        \fi%
        \protected@csxdef{lecsemnext@#2}{\csuse{@ltn}}%
  \fi
}
%
% Kept for backwards compatibility
% fs
\newcommand*\DefTypeFS[2]{%
  \DefSemType{fs}{#1}{#2}
}
% hs
\newcommand*\DefTypeHS[2]{%
  \DefSemType{hs}{#1}{#2}
}
% ss
\newcommand*\DefTypeSS[2]{%
  \DefSemType{ss}{#1}{#2}
}
% ws
\newcommand*\DefTypeWS[2]{%
  \DefSemType{ws}{#1}{#2}
}


%
% RETRIEVE COURSE INFORMATION
%

% 1) Course program
%
% Define labeling list if not available
\@ifundefined{labeling}{%
  \newenvironment{labeling}[2][]{%
    \def\sc@septext{#1}%
    \list{}{\settowidth{\labelwidth}{{%
        \textbf{#2\sc@septext}%
        }}%
      \leftmargin\labelwidth \advance\leftmargin by \labelsep
      \let\makelabel\labelinglabel
    }%
  }{%
    \endlist
  }
  \newcommand\labelinglabel[1]{%
    \textbf{#1\hfil\sc@septext}%
  }
}{}
%
% Program generation
\newcommand\makeprogram{%
  \raggedright
  \begin{ProgramList}
  \programlist
  \end{ProgramList}
}

% Exam schedule generation
\newcommand\makeexamprogram{%
  \raggedright
  \begin{ProgramListExam}
  \programlistexam
  \end{ProgramListExam}
}

% Customizable environments for formatting the lists

% ProgramList is the list used in programs
\newenvironment{ProgramList}{\begin{labeling}{\lecprogramlistindent}}{\end{labeling}}

% BeamerProgramList is the list used in programs
\newenvironment{BeamerProgramList}{\begin{description}[\lecprogramlistindent]}{\end{description}}

% ProgramListExam is the list used in exam schedules. By default identical to ProgramList
\newenvironment{ProgramListExam}{\begin{ProgramList}}{\end{ProgramList}}

% PresList is the list of presenting students
\newenvironment{PresList}{\begin{ProgramList}}{\end{ProgramList}}

% Same for beamer
\newenvironment{BeamerPresList}{\begin{BeamerProgramList}}{\end{BeamerProgramList}}
\newenvironment{BeamerProgramListExam}{\begin{BeamerProgramList}}{\end{BeamerProgramList}}

% Text format of program date
\newcommand*\programdateformat[1]{\textbf{#1}}
% Text format of program title
\newcommand*\sestitleformat[1]{#1}
% Text format of program title
\newcommand*\exsestitleformat[1]{\sestitleformat{#1}}
% Text format of canceled session titles
\newcommand*\cansestitleformat[1]{\textbf{#1}}
% Text format of block titles
\newcommand*\blocktitleformat[1]{\textbf{#1}}
% Text format of block numbers
\newcommand*\blocknumberformat[1]{\textbf{#1}}

% ProgramListItem, ProgramListExamItem and ProgramListCancelItem typeset a single
% session. Arguments: #1 date, #2 title, #3 title separator, #4 subtitle
\newcommand*{\ProgramListItem}[4]{\item[\programdateformat{#1}] \sestitleformat{#2#3#4}}
\newcommand*{\ProgramListCancelItem}[4]{\item[\programdateformat{#1}] \cansestitleformat{#2#3#4\leccancel}}
\newcommand*{\ProgramListExamItem}[4]{\item[\programdateformat{#1}] \exsestitleformat{#2#3#4}}

% Same for beamer program
\newcommand*{\BeamerProgramListItem}[4]{\item[\programdateformat{#1}] \sestitleformat{#2#3#4}}
\newcommand*{\BeamerProgramListCancelItem}[4]{\item[\programdateformat{#1}] \cansestitleformat{#2#3#4\leccancel}}
\newcommand*{\BeamerProgramListExamItem}[4]{\item[\programdateformat{#1}] \exsestitleformat{#2#3#4}}

% PresListItem: Program line for student presentation lists
\newcommand*\PresListItem[4]{%
  \ProgramListItem{#1}{#2}{#3}{#4}%
}

\newcommand*\BeamerPresListItem[4]{%
  \BeamerProgramListItem{#1}{#2}{#3}{#4}%
}

% Format break event
\newcommand*\breakevent[3]{\ifx\empty#1 #2\else#1#2#3\fi}
% ProgramListBreak typesets a break.
% Optional argument is date range, #2 is name of break
\newcommand*{\ProgramListBreak}[2][\empty]%
{%
  \begin{center}
    (\breakevent{#1}{: }{#2})
  \end{center}%
}

% ProgramListBlock
\newenvironment{ProgramListBlock}[2]%
 {%
  \ProgramBlockItem{#1}{#2}
  \begin{ProgramList}%
 }%
 {\end{ProgramList}}

\newcommand*{\ProgramBlockItem}[2]{\item[\blocknumberformat{#1}.] \blocktitleformat{#2}}
\newcommand*{\BeamerProgramBlockItem}[2]{\item[\blocknumberformat{#1}.] \blocktitleformat{#2}}
\newcommand*{\BeamerProgramBlockBlocksOnlyItem}[2]{\item[#1.] #2}

%
% Beamer program generation
\newif\if@jslp@beamerprogram@alerted\@jslp@beamerprogram@alertedfalse
\newif\if@jslp@beamerprogram@blocksonly\@jslp@beamerprogram@blocksonlyfalse
\newif\if@jslp@beamerprogram@uncover\@jslp@beamerprogram@uncoverfalse

\DeclareKeys[beamerprogram]
{
  % title=<title>
  title.store = \@bptitle,
  % options = <options>
  options.store = \@bpopts,
  % listoptions = <options>
  listoptions.store = \@bplistopts,
  % overlayarg = <arg>
  overlayarg.store = \@bpolarg,
  % overlayarg2 = <arg>
  overlayarg2.store = \@bpolargii,
  % overlayarg3 = <arg>
  overlayarg3.store = \@bpolargiii,
  % overlayarg4 = <arg>
  overlayarg4.store = \@bpolargiv,
  % overlayarg = <true|false> [not functional!]
  alerted.if = @jslp@beamerprogram@alerted,
  % blocksonly = <true|false>
  blocksonly.if = @jslp@beamerprogram@blocksonly,
  % uncover = <true|false>
  uncover.if = @jslp@beamerprogram@uncover
}

% Overlay specifications for uncover programs
\newcommand*\beameruncoverspec{\beamerdefaultoverlayspecification{<+(1)->}}
\newcommand*\beameruncoverffslidesspec{\beamerdefaultoverlayspecification{<+(-1)->}}
\newcommand*\beameruncoverblocksonlyspec{\beamerdefaultoverlayspecification{<+->}}
\newcommand*\beameralertspec{}

\newcommand*\makebeamerprogram[1][]{%
  \csdef{@bptitle}{\lecprogram}
  \def\btitleapp{}
  \numdef\pframes{\thefbreaks + 1}
  \SetKeys[beamerprogram]{alerted=false}
  \SetKeys[beamerprogram]{blocksonly=false}
  \SetKeys[beamerprogram]{uncover=false}
  \SetKeys[beamerprogram]{#1}
  \def\bpdescbeg{\begin{BeamerProgramList}}
  \providebool{alerted}
  \if@jslp@beamerprogram@alerted
     \booltrue{alerted}
  \else
     \boolfalse{alerted}
  \fi
  \providebool{uncoveredlist}
  \if@jslp@beamerprogram@uncover
     \booltrue{uncoveredlist}
  \else
     \boolfalse{uncoveredlist}
  \fi
  \if@jslp@beamerprogram@blocksonly
     \ifbool{alerted}{%
       \ifbool{uncoveredlist}%
           {\renewcommand*\beameruncoverblocksonlyspec{\beamerdefaultoverlayspecification{<+-| alert@+>}}}%
           {\renewcommand*\beameralertspec{\beamerdefaultoverlayspecification{<alert@+>}}}%
     }{}
     \ifcsvoid{@bpolarg}{%
       \ifcsvoid{@bpopts}{%
           \begin{frame}[label=beamerprogram]{\csuse{@bptitle}\btitleapp}
        }{%
           \begingroup\edef\tempa{\endgroup\noexpand%
             \begin{frame}[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
        }%
     }{%
       \ifcsvoid{@bpopts}{%
           \begin{frame}<\csuse{@bpolarg}>[label=beamerprogram]{\csuse{@bptitle}\btitleapp}
        }{%
           \begingroup\edef\tempa{\endgroup\noexpand%
             \begin{frame}<\csuse{@bpolarg}>[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
        }%
     }%
       \ifbool{uncoveredlist}{\beameruncoverblocksonlyspec}{\beameralertspec}
       \begin{BeamerProgramList}
         \ifcsempty{programblocklistbeamer}{\BeamerProgramBlockBlocksOnlyItem{}{}}{\programblocklistbeamer}
       \end{BeamerProgramList}
     \end{frame}
  \else% not \if@jslp@beamerprogram@blocksonly
    \ifbool{alerted}{%
       \ifbool{uncoveredlist}%
           {%
             \renewcommand*\beameruncoverspec{\beamerdefaultoverlayspecification{<+(1)-| alert@+(1)>}}
             \renewcommand*\beameruncoverffslidesspec{\beamerdefaultoverlayspecification{<+(-1)-| alert@+(-1)>}}
           }%
           {\renewcommand*\beameralertspec{\beamerdefaultoverlayspecification{<alert@+(1)>}}}%
     }{}
    % All but last slide(s) are generated in what follows
    \@ifundefined{programlistbeamerii}{}{%
    \def\btitleapp{\ (1/\pframes)}
     \ifcsvoid{@bpolarg}{%
        \ifcsvoid{@bpopts}{%
           \begin{frame}[label=beamerprogram]{\csuse{@bptitle}\btitleapp}
        }{%
           \begingroup\edef\tempa{\endgroup\noexpand%
             \begin{frame}[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
        }%
    }{%
        \ifcsvoid{@bpopts}{%
           \begin{frame}<\csuse{@bpolarg}>[label=beamerprogram]{\csuse{@bptitle}\btitleapp}
        }{%
           \begingroup\edef\tempa{\endgroup\noexpand%
             \begin{frame}<\csuse{@bpolarg}>[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
        }%
     }%
     \ifbool{uncoveredlist}{\beameruncoverspec}{\beameralertspec}
     \begin{BeamerProgramList}
      \programlistbeamerii
     \end{BeamerProgramList}
    \end{frame}
    }
    \@ifundefined{programlistbeameriii}{}{%
    \def\btitleapp{\ (2/\pframes)}
    \ifcsvoid{@bpolargii}{%
        \ifcsvoid{@bpopts}{%
           \begin{frame}[label=beamerprogram2]{\csuse{@bptitle}\btitleapp}
        }{%
           \begingroup\edef\tempa{\endgroup\noexpand%
              \begin{frame}[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
        }%
    }{%
        \ifcsvoid{@bpopts}{%
           \begin{frame}<\csuse{@bpolargii}>[label=beamerprogram2]{\csuse{@bptitle}\btitleapp}
        }{%
           \begingroup\edef\tempa{\endgroup\noexpand%
             \begin{frame}<\csuse{@bpolargii}>[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
        }%
     }%
     \ifbool{uncoveredlist}{\beameruncoverffslidesspec}{\beameralertspec}
     \begin{BeamerProgramList}
      \programlistbeameriii
     \end{BeamerProgramList}
    \end{frame}
    }
    \@ifundefined{programlistbeameriv}{}{%
    \def\btitleapp{\ (3/\pframes)}
    \ifcsvoid{@bpolargiii}{%
        \ifcsvoid{@bpopts}{%
           \begin{frame}[label=beamerprogram3]{\csuse{@bptitle}\btitleapp}
        }{%
           \begingroup\edef\tempa{\endgroup\noexpand%
             \begin{frame}[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
        }%
    }{%
        \ifcsvoid{@bpopts}{%
           \begin{frame}<\csuse{@bpolargiii}>[label=beamerprogram3]{\csuse{@bptitle}\btitleapp}
        }{%
           \begingroup\edef\tempa{\endgroup\noexpand%
             \begin{frame}<\csuse{@bpolargiii}>[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
        }%
     }%
     \ifbool{uncoveredlist}{\beameruncoverffslidesspec}{\beameralertspec}
     \begin{BeamerProgramList}
      \programlistbeameriv
     \end{BeamerProgramList}
    \end{frame}
    }
    % The last slide is generated separately:
    \ifnumgreater{\thefbreaks}{0}{\def\btitleapp{\ (\pframes/\pframes)}}{}
       \@ifundefined{programlistbeamerii}{%
          \ifcsvoid{@bpolarg}{%
             \ifcsvoid{@bpopts}{%
               \begin{frame}[label=beamerprogram]{\csuse{@bptitle}\btitleapp}
            }{%
               \begingroup\edef\tempa{\endgroup\noexpand%
               \begin{frame}[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
             }%
          }{%
              \ifcsvoid{@bpopts}{%
                 \begin{frame}<\csuse{@bpolarg}>[label=beamerprogram]{\csuse{@bptitle}\btitleapp}
             }{%
                 \begingroup\edef\tempa{\endgroup\noexpand%
                 \begin{frame}<\csuse{@bpolarg}>[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
             }%
          }%
        }{%
          \@ifundefined{programlistbeameriii}{%
             \ifcsvoid{@bpolargii}{%
               \ifcsvoid{@bpopts}{%
                 \begin{frame}[label=beamerprogram2]{\csuse{@bptitle}\btitleapp}
               }{%
                 \begingroup\edef\tempa{\endgroup\noexpand%
                 \begin{frame}[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
               }%
             }{%
               \ifcsvoid{@bpopts}{%
                 \begin{frame}<\csuse{@bpolargii}>[label=beamerprogram2]{\csuse{@bptitle}\btitleapp}
               }{%
                 \begingroup\edef\tempa{\endgroup\noexpand%
                 \begin{frame}<\csuse{@bpolargii}>[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
               }%
             }%
          }{%
             \@ifundefined{programlistbeameriv}{%
                    \ifcsvoid{@bpolargiii}{%
                        \ifcsvoid{@bpopts}{%
                           \begin{frame}[label=beamerprogram3]{\csuse{@bptitle}\btitleapp}
                        }{%
                           \begingroup\edef\tempa{\endgroup\noexpand%
                           \begin{frame}[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
                        }%
                    }{%
                       \ifcsvoid{@bpopts}{%
                           \begin{frame}<\csuse{@bpolargiii}>[label=beamerprogram3]{\csuse{@bptitle}\btitleapp}
                        }{%
                          \begingroup\edef\tempa{\endgroup\noexpand%
                           \begin{frame}<\csuse{@bpolargiii}>[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
                        }%
                    }%
             }{%
                  \ifcsvoid{@bpolargiv}{%
                        \ifcsvoid{@bpopts}{%
                           \begin{frame}[label=beamerprogram4]{\csuse{@bptitle}\btitleapp}
                        }{%
                           \begingroup\edef\tempa{\endgroup\noexpand%
                           \begin{frame}[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
                        }%
                    }{%
                       \ifcsvoid{@bpopts}{%
                           \begin{frame}<\csuse{@bpolargiv}>[label=beamerprogram4]{\csuse{@bptitle}\btitleapp}
                        }{%
                          \begingroup\edef\tempa{\endgroup\noexpand%
                           \begin{frame}<\csuse{@bpolargiv}>[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
                        }%
                    }%
             }%
          }%
      }%
     \ifbool{uncoveredlist}{\beameruncoverffslidesspec}{\beameralertspec}
     \begin{BeamerProgramList}
      \programlistbeamer
     \end{BeamerProgramList}
    \end{frame}
  \fi%\else\if@jslp@beamerprogram@blocksonly
}


% Exam schedule generation
\newcommand\makebeamerexamprogram[1][]{%
  \csdef{@bptitle}{\lecprogram}
  \def\btitleapp{}
  \numdef\pframes{\thefbreaks + 1}
  \SetKeys[beamerprogram]{alerted=false}
  \SetKeys[beamerprogram]{blocksonly=false}
  \SetKeys[beamerprogram]{uncover=false}
  \SetKeys[beamerprogram]{#1}
  \def\bpdescbeg{\begin{BeamerProgramList}}
  \providebool{alerted}
  \if@jslp@beamerprogram@alerted
     \booltrue{alerted}
  \else
     \boolfalse{alerted}
  \fi
  \providebool{uncoveredlist}
  \if@jslp@beamerprogram@uncover
     \booltrue{uncoveredlist}
  \else
     \boolfalse{uncoveredlist}
  \fi
  \if@jslp@beamerprogram@blocksonly
  \else% not \if@jslp@beamerprogram@blocksonly
    \ifbool{alerted}{%
       \ifbool{uncoveredlist}%
           {\renewcommand*\beameruncoverspec{\beamerdefaultoverlayspecification{<+(1)-| alert@+(1)>}}}%
           {\renewcommand*\beameralertspec{\beamerdefaultoverlayspecification{<alert@+(1)>}}}%
     }{}
    % All but last slide(s) are generated in what follows
    \ifcsempty{programlistbeamerexam}{}{%
     \def\btitleapp{}
      \ifcsvoid{@bpolarg}{%
         \ifcsvoid{@bpopts}{%
            \begin{frame}[label=beamerprogram]{\csuse{@bptitle}\btitleapp}
         }{%
            \begingroup\edef\tempa{\endgroup\noexpand%
              \begin{frame}[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
         }%
     }{%
         \ifcsvoid{@bpopts}{%
            \begin{frame}<\csuse{@bpolarg}>[label=beamerprogram]{\csuse{@bptitle}\btitleapp}
         }{%
            \begingroup\edef\tempa{\endgroup\noexpand%
              \begin{frame}<\csuse{@bpolarg}>[\csuse{@bpopts}]{\csuse{@bptitle}\btitleapp}}\tempa
         }%
      }%
      \ifbool{uncoveredlist}{\beameruncoverspec}{\beameralertspec}
      \begin{BeamerProgramListExam}
       \programlistbeamerexam
      \end{BeamerProgramListExam}
     \end{frame}
   }%
  \fi%\else\if@jslp@beamerprogram@blocksonly
}


% 2) Bibliography
%
\newcommand\makesessionbib{%
  \jsbiblist
}


% 3) Next term
%
\newcommand*\adjsemester{%
   \def\lecnyear{\lecyear}%
   \ifthenelse{\equal{\lecnsemny}{y}}{%
       \def\lecnyear{\the\numexpr\lecyear+1\relax}%
   }{}%
   \lecnsemshort~\lecnyear%
}

\newcommand*\adjsemesterverb{%
   \def\lecnyear{\lecyear}%
   \ifthenelse{\equal{\lecnsemny}{y}}{%
       \def\lecnyear{\the\numexpr\lecyear+1\relax}%
   }{}%
   \lecnsemverb~\lecnyear%
}

%
% COURSE SCHEDULE SETUP
%

% 1) Session definition
%
\newtoggle{shortinstrdef}
\newif\if@jslp@session@cancel\@jslp@session@cancelfalse
\newif\if@jslp@session@draft\@jslp@session@draftfalse
\newif\if@jslp@session@exam\@jslp@session@examfalse

\DeclareKeys[session]
{
  % titlesep = <sep>
  titlesep.code = { \csdef{@sestitlesep}{{#1}} },
  % subtitle = <title>
  subtitle.code = { \csdef{@sessubtitle}{{#1}} },
  % shorttitle = <title>
  shorttitle.code = {
    \csdef{@sesshorttitle}{{#1}}
    \csdef{@usesshorttitle}{{#1}}
  },
  % bibsec = <keyword>
  bibsec.store = \@sesbibsec,
  % room = <room>
  room.code = { \csdef{@sesroom}{{#1}} },
  % starttime = <starttime>
  starttime.code = {
    \csdef{@sesrtime}{#1}
    \csdef{@sestime}{\DTMtime{#1}}
  },
  % duration = <duration>
  duration.store = \@sesduration,
  % instructor = <instructor>
  instructor.code = {
    \csdef{@sesinstructor}{{#1}}
    \csdef{@usesinstructor}{{#1}}
    \iftoggle{shortinstrdef}{}{%
      \csdef{@sesshortinstructor}{{#1}}
      \csdef{@usesshortinstructor}{{#1}}%
    }
  },
  % shortinstructor = <instructor>
  shortinstructor.code = {
    \csdef{@sesshortinstructor}{{#1}}
    \csdef{@usesshortinstructor}{{#1}}
    \toggletrue{shortinstrdef}
  },
  % presstudents = <instructor>
  presstudents.code = { \csdef{@sespresstudents}{{#1}} },
  % cancel = <true|false>
  cancel.if = @jslp@session@cancel,
  % draft = <true|false>
  draft.if = @jslp@session@draft,
  % exam = <true|false>
  exam.if = @jslp@session@exam,
  % topicnumber = <true|false>
  topicnumber.code = {
    \setcounter{sestopic}{#1-1}
  },
  % extradate = <date>
  extradate.store = \@xsesdate
}

%
\newcommand*\NewSession[2][]{%
  \stepcounter{sesunit}
  \setcounter{snum}{\thesesunit-\thecancellations}
  \protected@csxdef{sesnr\thesnum}{\thesnum}
  \togglefalse{shortinstrdef}
  \csdef{@sestitlesep}{\ifcsempty{@sessubtitle}{}{\sestitlesep}}
  \csdef{@sessubtitle}{}
  \csdef{@sesshorttitle}{#2}
  \csdef{@usesshorttitle}{}
  \csdef{@sesbibsec}{}
  \csdef{@sesroom}{\lecroom}
  \csdef{@sestime}{\lecstarttime}
  \csdef{@sesrtime}{\@lecstarttime}
  \csdef{@sesduration}{\lecduration}
  \csdef{@sesinstructor}{\lecinstructor}
  \csdef{@sesshortinstructor}{\lecshortinstructor}
  \csdef{@usesinstructor}{}
  \csdef{@usesshortinstructor}{}
  \csdef{@sespresstudents}{}
  \csdef{@xsesdate}{}
  \SetKeys[session]{cancel=false}
  \SetKeys[session]{draft=false}
  \SetKeys[session]{exam=false}
  \SetKeys[session]{#1}
  \csdef{@sestitle}{#2}
  % only calculate the date if it is not fixed via extradate.
  \ifcsempty{@xsesdate}{%
     \setcounter{dateratio}{(\thesesunit-1)*\thelecinterval+\thesesoffset}
     \ifnumcomp{\value{autooffsettrigger}}{>}{0}{%
       \ifnumcomp{\value{autooffsettrigger}}{=}{\value{autooffsetcounter}}{%
       \addtocounter{sesoffset}{\theautooffset}%
       \setcounter{autooffsetcounter}{1}%
       }{\stepcounter{autooffsetcounter}}
     }{}
     \protected@csxdef{sesdate\thesnum}{%
       \bgroup\ifx\lecstartdate\empty\else\jslp@SetDate[\lecstartdate]\fi%
       \DTMsetdatestyle{lecdate}\DTMdate{\year-\month-\day+\thedateratio}\egroup}
     \protected@csxdef{sesshortdate\thesnum}{%
       \bgroup\ifx\lecstartdate\empty\else\jslp@SetDate[\lecstartdate]\fi%
       \DTMsetdatestyle{lecshortdate}\DTMdate{\year-\month-\day+\thedateratio}\egroup}
     \protected@csxdef{sesdtmdate\thesnum}{%
       \bgroup\ifx\lecstartdate\empty\else\jslp@SetDate[\lecstartdate]\fi%
       \DTMdate{\year-\month-\day+\thedateratio}\egroup}
  }{%
     \protected@csxdef{sesdate\thesnum}{%
       \bgroup\DTMsetdatestyle{lecdate}\expandafter\DTMdate{\csuse{@xsesdate}}\egroup}
     \protected@csxdef{sesshortdate\thesnum}{%
       \bgroup\DTMsetdatestyle{lecshortdate}\expandafter\DTMdate{\csuse{@xsesdate}}\egroup}
     \protected@csxdef{sesdtmdate\thesnum}{%
       \bgroup\expandafter\DTMdate{\csuse{@xsesdate}}\egroup}
  }
  \protected@csxdef{sestitle\thesnum}{\csuse{@sestitle}\ifcsempty{@sestitle}{\strut}{}}
  \protected@csxdef{sestitlesep\thesnum}{\csuse{@sestitlesep}}
  \protected@csxdef{sessubtitle\thesnum}{\csuse{@sessubtitle}}
  \protected@csxdef{sesshorttitle\thesnum}{\csuse{@sesshorttitle}}
  \protected@csxdef{usesshorttitle\thesnum}{\csuse{@usesshorttitle}}
  \protected@csxdef{sesbib\thesnum}{\csuse{@sesbibsec}}
  \protected@csxdef{sesroom\thesnum}{\csuse{@sesroom}}
  \protected@csxdef{sestime\thesnum}{\csuse{@sestime}}
  \protected@csxdef{sesrtime\thesnum}{\csuse{@sesrtime}}
  \protected@csxdef{sesduration\thesnum}{\csuse{@sesduration}}
  \protected@csxdef{sesinstructor\thesnum}{\csuse{@sesinstructor}}
  \protected@csxdef{sesshortinstructor\thesnum}{\csuse{@sesshortinstructor}}
  \protected@csxdef{usesinstructor\thesnum}{\csuse{@usesinstructor}}
  \protected@csxdef{usesshortinstructor\thesnum}{\csuse{@usesshortinstructor}}
  \protected@csxdef{sespresstudents\thesnum}{\csuse{@sespresstudents}}
  \protected@csxdef{sesblock\thesnum}{\csuse{@currentblock}}
  \protected@csxdef{sesblockno\thesnum}{\csuse{@currentblockno}}
  \if@jslp@session@cancel
    \stepcounter{cancellations}
    \protected@eappto\programlist{\noexpand\ProgramListCancelItem{\csuse{sesshortdate\thesnum}}{\csuse{sestitle\thesnum}}{\csuse{@sestitlesep}}{\csuse{@sessubtitle}}}
    \protected@eappto\programlistbeamer{\noexpand\BeamerProgramListCancelItem{\csuse{sesshortdate\thesnum}}{\csuse{sestitle\thesnum}}{\csuse{@sestitlesep}}{\csuse{@sessubtitle}}}
  \else
    \if@jslp@session@exam
        \stepcounter{exams}
        \protected@csxdef{examsesno\theexams}{\thesnum}
        \protected@eappto\programlistexam{\noexpand\ProgramListExamItem{\csuse{sesshortdate\thesnum}}{\csuse{sestitle\thesnum}}{\csuse{@sestitlesep}}{\csuse{@sessubtitle}}}
        \protected@eappto\programlistbeamerexam{\noexpand\BeamerProgramListExamItem{\csuse{sesshortdate\thesnum}}{\csuse{sestitle\thesnum}}{\csuse{@sestitlesep}}{\csuse{@sessubtitle}}}
        \ifcsempty{sesbib\thesnum}{}{%
        \xappto\jsbiblist{\noexpand\section{\csuse{sestitle\thesnum}\csuse{@sestitlesep}\csuse{@sessubtitle}}%
          \noexpand\nocite{*}%
          \noexpand\printbibliography[keyword=\csuse{sesbib\thesnum},heading=none]}%
        }%
    \else
        \stepcounter{sestopic}
        \if@jslp@session@draft
            \ifcsempty{@sestitle}{\protected@csxdef{sestitle\thesnum}{\sestopic}}{}
        \fi
        \protected@eappto\programlist{\noexpand\ProgramListItem{\csuse{sesshortdate\thesnum}}{\csuse{sestitle\thesnum}}{\csuse{@sestitlesep}}{\csuse{@sessubtitle}}}
        \protected@eappto\programlistbeamer{\noexpand\BeamerProgramListItem{\csuse{sesshortdate\thesnum}}{\csuse{sestitle\thesnum}}{\csuse{@sestitlesep}}{\csuse{@sessubtitle}}}
        \ifcsempty{sesbib\thesnum}{}{%
        \xappto\jsbiblist{\noexpand\section{\csuse{sestitle\thesnum}\csuse{@sestitlesep}\csuse{@sessubtitle}}%
          \noexpand\nocite{*}%
          \noexpand\printbibliography[keyword=\csuse{sesbib\thesnum},heading=none]}%
        }%
      \fi
  \fi
}

% 2) Semester breaks and schedule offsets
%
% Set break of one interval unit
\newcommand*\SetBreak[2][\empty]{%
  \stepcounter{sesunit}
  \stepcounter{cancellations}
  \ifnumcomp{\value{autooffsettrigger}}{>}{0}{%
     \ifnumcomp{\value{autooffsettrigger}}{=}{\value{autooffsetcounter}}{%
        \addtocounter{sesoffset}{\theautooffset}%
        \setcounter{autooffsetcounter}{1}%
     }{\stepcounter{autooffsetcounter}}
  }{}
  \ifx\empty#1
    \protected@eappto\programlist{\noexpand\ProgramListBreak{#2}}
    \protected@eappto\programlistbeamer{\noexpand\begin{center} (#2) \noexpand\end{center}}
  \else
    \protected@eappto\programlist{\noexpand\ProgramListBreak[#1]{#2}}
    \protected@eappto\programlistbeamer{\noexpand\begin{center} (#1: #2) \noexpand\end{center}}
  \fi
}

% Set break of multiple interval units
\DeclareKeys[break]
{
  % units = <int>
  units.store = \@breakunits,
  % span = <int>
  span.store = \@breakspan,
  % weeks = <int> (deprecated!)
  weeks.code = {
    \PackageWarning{jslectureplanner}{%
        \protect\SetBreaks\space option 'weeks' is deprecated. Use 'units' instead.}%
    \SetKeys[break]{units=#1}%
  }
}

\newcommand*\SetBreaks[2][units=1]{%
  \csdef{@breakunits}{}
  \csdef{@breakspan}{}
  \SetKeys[break]{#1}
  \setcounter{breakunits}{\csuse{@breakunits}}
  \setcounter{sesunit}{\thesesunit+\thebreakunits}
  \setcounter{cancellations}{\thecancellations+\thebreakunits}
  \setcounter{loopcounter}{0}
  \loop\ifnum\theloopcounter<\thebreakunits\relax
     \ifnumcomp{\value{autooffsettrigger}}{>}{0}{%
        \ifnumcomp{\value{autooffsettrigger}}{=}{\value{autooffsetcounter}}{%
          \addtocounter{sesoffset}{\theautooffset}%
          \setcounter{autooffsetcounter}{1}%
       }{\stepcounter{autooffsetcounter}}
    }{}
    \stepcounter{loopcounter}
  \repeat
  \ifcsempty{@breakspan}{%
    \protected@eappto\programlist{\noexpand\ProgramListBreak{#2}}
    \protected@eappto\programlistbeamer{\noexpand\begin{center} (#2) \noexpand\end{center}}
  }{%
    \protected@eappto\programlist{\noexpand\ProgramListBreak[\csuse{@breakspan}]{#2}}
    \protected@eappto\programlistbeamer{\noexpand\begin{center} (\csuse{@breakspan}: #2) \noexpand\end{center}}
  }
}

% Offset in days
\newcommand*\SetLecOffset[1]{%
    \addtocounter{sesoffset}{#1}
}

% Automatic Offset after n sessions
\newcommand*{\SetAutoOffset}[3][1]{%
    \setcounter{autooffsetcounter}{#1}
    \setcounter{autooffsettrigger}{#2}
    \setcounter{autooffset}{#3}
}

% 3) Definition of thematic blocks
%
\newtoggle{inblock}
\newcommand*\StartBlock[1]{%
  \stepcounter{blocks}%
  \protected@eappto\programlist{\noexpand\begin{ProgramListBlock}{\Roman{blocks}}{#1}}
  \protected@eappto\programlistbeamer{\noexpand\BeamerProgramBlockItem{\Roman{blocks}}{#1}}%
  \gappto\programlistbeamer{\begin{BeamerProgramList}}
  \protected@xappto\programblocklistbeamer{\noexpand\BeamerProgramBlockBlocksOnlyItem{\Roman{blocks}}{#1}}%
  \csxdef{@currentblock}{#1}%
  \csxdef{@currentblockno}{\Roman{blocks}}%
  \global\toggletrue{inblock}%
}

\newcommand*\EndBlock{%
  \gappto\programlist{\end{ProgramListBlock}}
  \gappto\programlistbeamer{\end{BeamerProgramList}}
  \csxdef{@currentblock}{}%
  \csxdef{@currentblockno}{}%
  \global\togglefalse{inblock}%
}

\newcommand*\NewBlock[1]{%
  \EndBlock
  \StartBlock{#1}
}

\newcommand*\@PauseBlock{%
  \gappto\programlistbeamer{\end{BeamerProgramList}}
}

\newcommand*\@ResumeBlock{%
  % the \item here is necessary since this is nested immediately into another list
  \gappto\programlistbeamer{\item \begin{BeamerProgramList}}
}

\newenvironment{SessionBlock}[1]{\StartBlock{#1}}{\EndBlock}

% 4) Beamer-specific features
%
% Beamer frame breaks
\newcommand*\SetBeamerFrameBreak{%
  \iftoggle{inblock}{\@PauseBlock}{}%
  \stepcounter{fbreaks}
  \ifdefined\programlistbeamerii
     \ifdefined\programlistbeameriii
        \global\let\programlistbeameriv\programlistbeamer
     \else
       \global\let\programlistbeameriii\programlistbeamer
     \fi
  \else%
    \global\let\programlistbeamerii\programlistbeamer
  \fi
  \global\let\programlistbeamer\empty
  \iftoggle{inblock}{\@ResumeBlock}{}%
}

% Beamer program hook
\newcommand*\SetBeamerHook[1]{%
    \protected@eappto\programlistbeamer{\noexpand#1}
}

% 5) Infrastructure
%
% Office hours
\newcommand\SetOfficeHours[1]{%
  \def\officehours{#1}%
}

% Office number
\newcommand\SetOfficeNumber[1]{%
  \def\officenumber{#1}%
}

% (E-learning) platform
\newcommand\SetPlatform[1]{%
  \def\lecplatform{#1}%
}


%
% 6) Student presentations
%

\newcounter{pressession}
\setcounter{pressession}{1}
\newcounter{lastpressession}
\providebool{deflastpressession}

% Allow to change first output session
\newcommand*\setfirstpressession[1]{%
  \setcounter{pressession}{#1}%
}

% Allow to change last output session
\newcommand*\setlastpressession[1]{%
  \setcounter{lastpressession}{#1}%
  \booltrue{deflastpressession}%
}

% Generate presentation list
\newcommand\makepreslist{%
  \@ifstar{\@makeblankpreslist}{\@makepreslist}%
}
\newcommand*\emptypressession{---}
\newcommand*\presseparator{\par}
% Unstarred: use sespresstudents
\newcommand\@makepreslist{%
  \ifbool{deflastpressession}{}{\setcounter{lastpressession}{\thesnum}}%
  \begin{PresList}
  \whiledo {\not{\value{pressession} > \value{lastpressession}}}%
  {%
    \ThisSession{\thepressession}%
    \if\relax\sespresstudents\relax
    \MakePresListLine{\thepressession}\presseparator%
    \emptypressession
    \else
    \MakePresListLine{\thepressession}\presseparator%
    \SessionPresStudents{\thepressession}
    \fi
    \stepcounter{pressession}%
  }
  \end{PresList}
}
\newlength\blankpreslistvspace
\setlength\blankpreslistvspace{2\baselineskip}
% Starred: blank list
\newcommand\@makeblankpreslist{%
  \ifbool{deflastpressession}{}{\setcounter{lastpressession}{\thesnum}}%
  \begin{PresList}
  \whiledo {\not{\value{pressession} > \value{lastpressession}}}%
  {%
    \MakePresListLine{\thepressession}\vspace{\blankpreslistvspace}
    \stepcounter{pressession}%
  }
  \end{PresList}
}

% A beamer-specific version
\newcommand*\beamerpresseparator{:\ }
\newcommand\makebeamerpreslist{%
  \ifbool{deflastpressession}{}{\setcounter{lastpressession}{\thesnum}}%
  \begin{BeamerPresList}
  \whiledo {\not{\value{pressession} > \value{lastpressession}}}%
  {%
    \MakeBeamerPresListLine{\thepressession}\beamerpresseparator%
    \SessionPresStudents{\thepressession}
    \stepcounter{pressession}%
  }
  \end{BeamerPresList}
}


%
% RETRIEVE SESSION-SPECIFIC INFORMATION
%

% Define current session
\newcommand\ThisSession[1]{%
  \gdef\sesnr{\csuse{sesnr#1}}%
  \gdef\sesdate{\csuse{sesdate#1}}%
  \gdef\sesshortdate{\csuse{sesshortdate#1}}%
  \gdef\sesdtmdate{\csuse{sesdtmdate#1}}%
  \gdef\sestitle{\csuse{sestitle#1}}%
  \gdef\sestitlesep{\csuse{sestitlesep#1}}%
  \gdef\sesshorttitle{\csuse{sesshorttitle#1}}%
  \gdef\@usesshorttitle{\csuse{usesshorttitle#1}}%
  \gdef\sessubtitle{\csuse{sessubtitle#1}}%
  \gdef\sesroom{\csuse{sesroom#1}}%
  \gdef\sesstarttime{\csuse{sestime#1}}%
  \gdef\sesendtime{\jslp@endtime{\csuse{sesrtime#1}}{\csuse{sesduration#1}}}%
  \gdef\sesslot{\jstimeslot{\sesstarttime}{\sesendtime}}%
  \gdef\@sesinstructor{\csuse{sesinstructor#1}}%
  \gdef\@sesshortinstructor{\csuse{sesshortinstructor#1}}%
  \gdef\@usesinstructor{\csuse{usesinstructor#1}}%
  \gdef\@usesshortinstructor{\csuse{usesshortinstructor#1}}%
  \gdef\sespresstudents{\csuse{sespresstudents#1}}%
  \gdef\sesblocktitle{\csuse{sesblock#1}}%
  \gdef\sesblocknumber{\csuse{sesblockno#1}}%
  \if\hfuzz\@usesinstructor\hfuzz%
    \global\togglefalse{uniquesesinstructor}%
  \else
    \global\toggletrue{uniquesesinstructor}%
  \fi
  \if\hfuzz\@usesshortinstructor\hfuzz%
    \global\togglefalse{uniquesesshortinstructor}%
  \else
    \global\toggletrue{uniquesesshortinstructor}%
  \fi
  \if\hfuzz\@usesshorttitle\hfuzz%
    \global\togglefalse{uniquesesshorttitle}%
  \else
    \global\toggletrue{uniquesesshorttitle}%
  \fi
}

% Define a local session
% (independent of current session)
\newcommand\LocalSession[1]{%
  \gdef\lsesnr{\csuse{sesnr#1}}%
  \gdef\lsesdate{\csuse{sesdate#1}}%
  \gdef\lsesshortdate{\csuse{sesshortdate#1}}%
  \gdef\lsesdtmdate{\csuse{sesdtmdate#1}}%
  \gdef\lsestitle{\csuse{sestitle#1}}%
  \gdef\lsestitlesep{\csuse{sestitlesep#1}}%
  \gdef\lsesshorttitle{\csuse{sesshorttitle#1}}%
  \gdef\lsessubtitle{\csuse{sessubtitle#1}}%
  \gdef\lsesroom{\csuse{sesroom#1}}%
  \gdef\lsesstarttime{\csuse{sestime#1}}%
  \gdef\lsesendtime{\jslp@endtime{\csuse{sesrtime#1}}{\csuse{sesduration#1}}}%
  \gdef\lsesslot{\jstimeslot{\lsesstarttime}{\lsesendtime}}%
  \gdef\@lsesinstructor{\csuse{sesinstructor#1}}%
  \gdef\@lsesshortinstructor{\csuse{sesshortinstructor#1}}%
  \gdef\@lusesinstructor{\csuse{usesinstructor#1}}%
  \gdef\@lusesshortinstructor{\csuse{usesshortinstructor#1}}%
  \gdef\lsespresstudents{\csuse{sespresstudents#1}}%
  \gdef\lsesblocktitle{\csuse{sesblock#1}}%
  \gdef\lsesblocknumber{\csuse{sesblockno#1}}%
}

% Get the session no of exam no #1
\newcommand*\examsesno[1]{%
   \csuse{examsesno#1}%
}

% \ses[short]instructor and \ses[short]instructor*.
% The starred versions only output something if the session
% instructor differs from the general lecture instructor
\newcommand\sesinstructor{\@ifstar{\@usesinstructor}{\@sesinstructor}}
\newcommand\sesshortinstructor{\@ifstar{\@usesshortinstructor}{\@sesshortinstructor}}
% same for local instructor macros 
\newcommand\lsesinstructor{\@ifstar{\@lusesinstructor}{\@lsesinstructor}}
\newcommand\lsesshortinstructor{\@ifstar{\@lusesshortinstructor}{\@lsesshortinstructor}}

% Get information for a specific (local) session
%
% Full title
\newcommand*\SessionFullTitle[1]{%
  \LocalSession{#1}%
  \lsestitle\lsestitlesep\lsessubtitle%
}

% Date
\newcommand*\SessionDate[1]{%
  \LocalSession{#1}%
  \lsesdate%
}

% Short title
\newcommand*\SessionShortTitle[1]{%
  \LocalSession{#1}%
  \lsesshorttitle%
}

% Main title
\newcommand*\SessionTitle[1]{%
  \LocalSession{#1}%
  \lsestitle%
}

% Short date
\newcommand*\SessionShortDate[1]{%
  \LocalSession{#1}%
  \lsesshortdate%
}

% Short date
\newcommand*\SessionDTMDate[1]{%
  \LocalSession{#1}%
  \lsesdtmdate%
}

% Time
\newcommand*\SessionStartTime[1]{%
  \LocalSession{#1}%
  \lsesstarttime%
}
% End Time
\newcommand*\SessionEndTime[1]{%
  \LocalSession{#1}%
  \lsesendtime%
}
% Time Slot
\newcommand*\SessionTimeSlot[1]{%
  \LocalSession{#1}%
  \lsesslot%
}

% Room
\newcommand*\SessionRoom[1]{%
  \LocalSession{#1}%
  \lsesroom%
}

% Instructor relay
\newcommand*\SessionInstructor{%
  \@ifstar{\@@SessionInstructor}{\@SessionInstructor}%
}

% Instructor, unstarred
\newcommand*\@SessionInstructor[1]{%
  \LocalSession{#1}%
  \lsesinstructor%
}

% Instructor, starred
\newcommand*\@@SessionInstructor[1]{%
  \LocalSession{#1}%
  \lsesinstructor*%
}

% Instructor (Short Form) relay
\newcommand*\SessionShortInstructor{%
  \@ifstar{\@@SessionShortInstructor}{\@SessionShortInstructor}%
}

% Instructor (Short Form), unstarred
\newcommand*\@SessionShortInstructor[1]{%
  \LocalSession{#1}%
  \lsesshortinstructor%
}

% Instructor (Short Form), starred
\newcommand*\@@SessionShortInstructor[1]{%
  \LocalSession{#1}%
  \lsesshortinstructor*%
}

% Presenting students
\newcommand*\SessionPresStudents[1]{%
  \LocalSession{#1}%
  \lsespresstudents%
}

% Session block title
\newcommand*\SessionBlockTitle[1]{%
  \LocalSession{#1}%
  \lsesblocktitle%
}

% Session block number
\newcommand*\SessionBlockNumber[1]{%
  \LocalSession{#1}%
  \lsesblocknumber%
}

% Program line suitable for
% a description or labeling list
\newcommand*\MakeProgramline[1]{%
  \LocalSession{#1}%
  \item[{\bfseries\lsesshortdate}]%
    \lsestitle\lsestitlesep\lsessubtitle%
}

% Program line suitable for preslist
\newcommand*\MakePresListLine[1]{%
  \LocalSession{#1}%
  \PresListItem{\lsesshortdate}{\lsestitle}{\lsestitlesep}{\lsessubtitle}%
}
\newcommand*\MakeBeamerPresListLine[1]{%
  \LocalSession{#1}%
  \BeamerPresListItem{\lsesshortdate}{\lsestitle}{\lsestitlesep}{\lsessubtitle}%
}

% Get information for adjacent (next, previous etc.) sessions
%
% Full title
\newcommand*\AdjSessionFullTitle[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionFullTitle{\theadjsession}%
  \fi
}
% Date
\newcommand*\AdjSessionDate[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionDate{\theadjsession}%
  \fi
}
% Short date
\newcommand*\AdjSessionShortDate[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionShortDate{\theadjsession}%
  \fi
}
% DTM Date
\newcommand*\AdjSessionDTMDate[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionDTMDate{\theadjsession}%
  \fi
}
% Time
\newcommand*\AdjSessionStartTime[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionStartTime{\theadjsession}%
  \fi
}
% Time
\newcommand*\AdjSessionEndTime[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionEndTime{\theadjsession}%
  \fi
}
% Time
\newcommand*\AdjSessionTimeSlot[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionTimeSlot{\theadjsession}%
  \fi
}
% Short title
\newcommand*\AdjSessionShortTitle[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionShortTitle{\theadjsession}%
  \fi
}
% Main title
\newcommand*\AdjSessionTitle[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionTitle{\theadjsession}%
  \fi
}
% Session block title
\newcommand*\AdjSessionBlockTitle[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionBlockTitle{\theadjsession}%
  \fi
}
% Session block number
\newcommand*\AdjSessionBlockNumber[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionBlockNumber{\theadjsession}%
  \fi
}
% Room
\newcommand*\AdjSessionRoom[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionRoom{\theadjsession}%
  \fi
}
% Instructor relay
\newcommand*\AdjSessionInstructor{%
  \@ifstar{\@@AdjSessionInstructor}{\@AdjSessionInstructor}%
}
% Instructor, unstarred
\newcommand*\@AdjSessionInstructor[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionInstructor{\theadjsession}%
  \fi
}
% Instructor, starred
\newcommand*\@@AdjSessionInstructor[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionInstructor*{\theadjsession}%
  \fi
}
% Instructor (Short Form) relay
\newcommand*\AdjSessionShortInstructor{%
  \@ifstar{\@@AdjSessionShortInstructor}{\@AdjSessionShortInstructor}%
}
% Instructor (Short Form), unstarred
\newcommand*\@AdjSessionShortInstructor[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionShortInstructor{\theadjsession}%
  \fi
}
% Instructor (Short Form), starred
\newcommand*\@@AdjSessionShortInstructor[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionShortInstructor*{\theadjsession}%
  \fi
}
% Presenting students
\newcommand*\AdjSessionPresStudents[1][1]{%
  \ifnum0<0\sesnr\relax
    \setcounter{adjsession}{\numexpr\sesnr+#1\relax}%
    \SessionPresStudents{\theadjsession}%
  \fi
}
%
%%%%%%%%%%%%%

%
% DEPRECATED THINGS
%

% Reset to today
% DEPRECATED as of v.0.8,
\newcommand*\ResetDate{%
  \PackageWarning{jslectureplanner}{%
    \protect\ResetDate\space is deprecated (not needed anymore).}%
}

% datetime (v.1) date formats
% DEPRECATED as of v.1.3
% Issue a warning if redefined.
\newcommand*\lecdateformat{}
\newcommand*\lecdateshortformat{}
\AtEndPreamble{%
  \ifcsempty{lecdateformat}{}{
    \PackageWarning{jslectureplanner}{\protect\lecdateformat\space is deprecated and non-functional.\MessageBreak
     Please refer to the manual for the new way of customizing date output.
    }
  }
  \ifcsempty{lecdateshortformat}{}{
    \PackageWarning{jslectureplanner}{\protect\lecdateshortformat\space is deprecated and non-functional.\MessageBreak
     Please refer to the manual for the new way of customizing date output.
    }
  }
}

% Finis
