summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Master/texmf-dist/doc/lualatex/semesterplannerlua/README.md43
-rw-r--r--Master/texmf-dist/doc/lualatex/semesterplannerlua/semesterplannerlua.pdfbin0 -> 144336 bytes
-rw-r--r--Master/texmf-dist/source/lualatex/semesterplannerlua/semesterplannerlua.dtx885
-rw-r--r--Master/texmf-dist/source/lualatex/semesterplannerlua/semesterplannerlua.ins59
-rw-r--r--Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua.sty256
-rw-r--r--Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_calendar.lua132
-rw-r--r--Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_dmenu.lua156
-rw-r--r--Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_timetable.lua233
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check2
-rw-r--r--Master/tlpkg/tlpsrc/collection-luatex.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/semesterplannerlua.tlpsrc0
11 files changed, 1766 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/lualatex/semesterplannerlua/README.md b/Master/texmf-dist/doc/lualatex/semesterplannerlua/README.md
new file mode 100644
index 00000000000..d7049942cb8
--- /dev/null
+++ b/Master/texmf-dist/doc/lualatex/semesterplannerlua/README.md
@@ -0,0 +1,43 @@
+# Readme for the package semesterplannerLua
+
+Author: Lukas Heindl (`oss.heindl+latex@protonmail.com`).
+
+CTAN page: not yet
+
+## License
+The LaTeX package `semesterplannerLua` is distributed under the LPPL 1.3 license.
+
+## Description
+
+The LaTeX package `semesterplannerLua` provides commands to print timetables, lists
+of appointments and exams. Also it is possible to draw calendars of specified
+ranges (and mark dates which were previously listed).
+
+## Installation
+
+For a manual installation:
+
+* put the files `semesterplannerlua.ins` and `semesterplannerlua.dtx` in the
+same directory;
+* run `latex semesterplannerlua.ins` in that directory.
+
+The file `semesterplannerlua.sty` will be generated.
+
+In addition to the `semesterplannerlua.sty` the files
+`semesterplannerLua_calendar.lua` and `semesterplannerLua_timetable.lua` are
+also required.
+You have to put them in the same directory as your document or (best) in a `texmf` tree.
+
+
+### Simplified version:
+
+* run `l3build unpack` to generate the `.sty` (and the `.lua` files) in
+`build/unpacked/`
+
+### Experimental: dmenu script
+There is also the `semesterplannerLua_dmenu.lua` script which will display the
+previous and next (and currently running) item from your timetable via dmenu,
+copying the url or the link to the TUM roomfinder(if set) to your clipboard if
+selected.
+
+You might want to adapt the roomfinder behaviour.
diff --git a/Master/texmf-dist/doc/lualatex/semesterplannerlua/semesterplannerlua.pdf b/Master/texmf-dist/doc/lualatex/semesterplannerlua/semesterplannerlua.pdf
new file mode 100644
index 00000000000..40ee78f8a3d
--- /dev/null
+++ b/Master/texmf-dist/doc/lualatex/semesterplannerlua/semesterplannerlua.pdf
Binary files differ
diff --git a/Master/texmf-dist/source/lualatex/semesterplannerlua/semesterplannerlua.dtx b/Master/texmf-dist/source/lualatex/semesterplannerlua/semesterplannerlua.dtx
new file mode 100644
index 00000000000..8341981afd2
--- /dev/null
+++ b/Master/texmf-dist/source/lualatex/semesterplannerlua/semesterplannerlua.dtx
@@ -0,0 +1,885 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2024 by Lukas Heindl <oss.heindl+latex@protonmail.com>
+% ---------------------------------------------------------------------------
+% 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 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is Lukas Heindl.
+%
+% This work consists of the files beamercolorthemeCatppuccin.dtx and beamercolorthemeCatppuccin.ins
+% and the derived filebase beamercolorthemeCatppuccin.sty.
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\ProvidesFile{semesterplannerlua.dtx}
+%</driver>
+%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
+%<package>\ProvidesPackage{semesterplannerlua}
+%<*package>
+ [2024/05/19 v1.1.1 Semesterplanner package in lua with tikz only]
+%</package>
+%
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage[a4paper,margin=25mm,left=50mm,nohead]{geometry}
+\usepackage[numbered]{hypdoc}
+\usepackage{array}
+\usepackage{semesterplannerlua}[2024/02/27]
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\begin{document}
+ \DocInput{\jobname.dtx}
+ \PrintChanges
+ \PrintIndex
+\end{document}
+%</driver>
+% \fi
+%
+% \CheckSum{362}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+%
+% \changes{v0.0.0}{2021/10/07}{First draft}
+% \changes{v0.0.1}{2022/04/28}{Added new options (providing day
+% representation in source code)}
+% \changes{v0.0.2}{2022/04/30}{Write out timetable data to be able to build
+% e.g. something with dmenu over it and provide an example dmenu lua
+% script}
+% \changes{v0.0.3}{2024/02/25}{Rename to semesterplannerLua and rewrite for
+% l3build}
+% \changes{v1.0.0}{2024/02/27}{First full release}
+% \changes{v1.1.0}{2024/05/19}{Make ready for CTAN}
+% \changes{v1.1.1}{2024/05/19}{Make ready for CTAN (2)}
+%
+%
+% \DoNotIndex{\newcommand,\newenvironment,\\,\begin,\end,\def,\definecolor,\directlua,\endinput,\faBullhorn,\faCamera,\faFlag,\faQuestion,\faTimesCircle,\faWarning,\faWindows,\faYoutubePlay,\node,\pgfkeys,\pgfkeysvalueof,\protected,\raggedright,\textbf,\textcolor,\textwidth,\unexpanded,\",\x,\y,\year,\week,\tiny,\tikz@lib@cal@xshift,\tikz@lib@cal@yshift,\tikz,\textit,\t,\section,\phantom,\pgftransformyshift,\pgftransformxshif,\pgfmathsetlength,\pgf@ya,\pgf@xa,\openout,\n,\newwrite,\month,\minuteToFrac,\matrix,\l,\jobname,\init,\immediate,\ignorespaces,\ifdate,\hfil,\href,\foreach,\faStickyNoteO,\faPencil,\faComment,\faClockO,\faCalendar,\faBold,\draw,\d,\day,\checkKeys,\%,\RequirePackage,\usepackage,\usetikzlibrary,\pgftransformxshift}
+%
+% \providecommand*{\url}{\texttt}
+% \GetFileInfo{semesterplannerlua.dtx}
+% \title{\textsf{semesterplannerLua} --- Semesterplanner package in lua
+% with tikz only
+% }
+% \author{Lukas Heindl \\ \url{oss.heindl+latex@protonmail.com} \\ \faGithub:
+% \url{https://github.com/atticus-sullivan/semesterplannerLua}}
+% \date{\fileversion~from \filedate}
+%
+% \maketitle
+%
+% \begin{abstract}
+% This package provides a mean to easily print a timetable e.g. for a
+% semesterplan. The reason for this package to exist is that I wanted to
+% reimplement \url{https://github.com/nlschn/semesterplanner/} with
+% printing the timetable with |tikz| only (which is more easily to be
+% modified) and with the ability of making entries spanning only a fraction
+% of the column (for showing simultanious events).
+%
+% Documents using this package need to be compiled with
+% LuaLaTeX. The package requires |xcolor|, |fontawesome|, |tikz| (and |pgfkeys|).
+% \end{abstract}
+%
+% \tableofcontents
+%
+% \section{Usage}
+% Load with |\usepackage{semesterplannerlua}|
+% \subsection{timetable}
+%
+% \DescribeEnv{timetable} |\begin{timetable}[opts]...\end{timetable}|\\
+% This is the core environment of this package. Within it you can use
+% |\lecture|, |\seminar|, |\tutorial|, |\officehour| and |\meeting|. All
+% these commands are only defined inside the |timetable| environment, and
+% have the same structure. It typesets a timetable with the specified
+% entries. If you have a look at the |.sty| file you'll see that these
+% macros just take a general macro and set some default values before. Thus
+% it is easy to define new ones (keep in mind that you'll need
+% |\makeatletter|) to access the general macro.
+%
+% Writes out a file containing the data from the timetable (your events) to
+% be able to have just the |.tex| file containing the timetable, but do
+% some scriping on the data (e.g. show the last, current and next events).
+% For simplicity the data is stored in lua-syntax (|return|s a table of the
+% events). This way we don't need to worry about any string escaping (like
+% with csv) and no complicated parsers are needed. Be aware though that a
+% simple |events = dofile"path"| has risks since |"path"| might contain lua
+% code which is simply executed that way.
+%
+% |opts| are optional arguments (enclosed with |{}|) separated with |,|:
+% \begin{description}
+% \item[|days|] List of the names of the days that should be set as
+% column names. Note that if you specify only 4 names only these 4
+% columns will be printed (with the first day being identified as
+% Monday)
+% \textit{Default: |Mon,Thue,Wend,Thur,Fri|}
+% \item[|dayse|] List of strings used in the code to idenfity the day.
+% This list is kind of a mapping string $\to$ integer.
+% \item[|start time|] Explicit start-time of the timetable given in minutes
+% (|HH*60 + MM|). Can be set as |start time/.evaluated={HH*60 + MM}|.
+% If this is empty, the start time is derived from the given events.
+% \textit{Default: |""|}
+% \item[|end time|] Equivalent to |start-time|
+% \textit{Default: |""|}
+% \item[|width|] Give the width of the timetable. (can be given e.g. as
+% |\textwidth| as this is directly given to tikz).
+% \textit{Default:} |\textwidth|
+% \item[|length|] Give the length of the timetable (measured in |cm|)
+% (has to be a straight number since this is needed in calculation)
+% \textit{Default: 10}
+% \end{description}
+%
+% \DescribeMacro{\lecture} |\lecture [opts]|
+%
+% \DescribeMacro{\tutorial} |\tutorial [opts]|
+%
+% \DescribeMacro{\seminar} |\seminar [opts]|
+%
+% \DescribeMacro{\officehour} |\officehour[opts]|
+%
+% \DescribeMacro{\meeting} |\meeting [opts]|
+%
+% |opts| are optional arguments (enclosed with |{}|) separated with |,|:
+% \begin{description}
+% \item[|title|] Give the name of the lecture
+% \item[|speaker|] Give the name of the lecturer
+% \item[|location|] Give the place of the event (most probably the room or
+% an online plattform, see \ref{icons}). If you want to use
+% |\href{url}{string repr}|, keep in mind that you need to
+% |\unescaped{}| it, since all input to lua has to be text
+% \item[|day|] The weekday on which the event takes place. Has to be
+% one of those you specified in |dayse| (or by default: |M|,|T|,|W|,|Th|,|F|)
+% \item[|time|] The timespan of the event formatted as |HH:MM-HH:MM|
+% (24H clock)
+% \item[|prio|] The priority of the event (see \ref{icons})
+% \item[|scale width|] Specify the width of the entry in fractions
+% of column (use |0.5| to span half the column).
+% \item[|offset|] Shift the entry to the right. Specified in fractions
+% of column.
+% \item[|password|] Original purpose: Only included in the file written
+% out with the timetable data, to be able to make a script which
+% quickly copies url (from |location|) and |password| to the clipboard.
+% \item[|type|] Only included in the file written out with the
+% timetable data as well (Original purpose: To be able to exclude some
+% types)
+% \item[|tikz|] Free customizable event code. See the documentation
+% at the end for keys that can be used here (all keys in |/event|). To
+% simply pass arguments to the tikz-node that is being created for the
+% event use |tikz/.append={your arguments}| (be careful with |text width|,
+% |text height|, |text depth| as these keys are being used for
+% the dimensions of the node as well as with |anchor|)
+% \item[|content|] Is usually set automatically based on the other keys
+% (|title|for instance). This key can override this.
+% \item[|textcolor|] Usually set by the type of macro used
+% \item[|formatter|] internal stub for providing different formatting
+% options. Formatting functions need to be specified in the
+% |-timetable.lua| file
+% \end{description}
+% The entries |Day| and |Time| are mandatory since they are needed for the
+% positioning of the node. All others are merely necessary for the content
+% of the node and are therefore nor mandatory.
+%
+% \subsubsection{Special Notes}
+% Note that the |length| argument does specify the length of the timetable
+% without taking account of the column headers.
+%
+% Same goes for the |width| parameter regarding the labels containing the
+% time on the right. Since in this case any tex-lenght is allowed, you can
+% simply try to subtract the length of the clock label using something like
+% |\settowidth{\length}{12:30}| to set a length to the length of a clock
+% label and then subtract this from the length you want to specify.
+%
+% \hangindent=4.5em \hangafter=1 \textbf{Hint:} The content of the
+% environment isn't processed by this package. Only the event commands (so
+% to speak |\lecture|,|\tutorial|,|\seminar|,|\officehour|,|\meeting| are
+% relevant. All other contents are set immediately before the timetable.
+% Therefore, if you wan to add e.g. a |\hspace*{10cm}| to shift the
+% timetable to the left, the last line of the env would be the place to do
+% so (there musn't be an empty line below since otherwise a new paragraph
+% is started).
+%
+% \newpage
+% \subsubsection{Example}
+% |\begin{timetable}[|\\
+% | days={Mon,Thue,Wend,Thur,Fri},|\\
+% | start time/.evaluated={11*60}, end time/.evaluated={15*60}|\\
+% | ]|\\
+% | \lecture[title={TestingLectureLongOne},speaker={Doe},|\\
+% | location={RN1},day={W},time={12:30-13:30}]|\\
+% | \lecture[title={TestingLectureLongOne},speaker={John},|\\
+% | location={RN1},day={Th},time={12:30-13:30},offset=0.5,scale width=0.5]|\\
+% | \lecture[title={TestingLectureLongOne},speaker={Dr. Doe},|\\
+% | location={\zoom},day={T},time={12:30-13:30},prio={\phigh}]|\\
+% |\end{timetable}|\\
+%
+% \begin{timetable}[days={Mon,Thue,Wend,Thur,Fri}, start
+% time/.evaluated={11*60}, end time/.evaluated={15*60}]
+% \lecture[title={TestingLectureLongOne}, speaker={Heindl}, location={RN1}, day={W}, time={12:30-13:30}]
+% \lecture[title={TestingLectureLongOne}, speaker={Heindl}, location={RN1}, day={Th}, time={12:30-13:30}, offset=0.5, scale width=0.5]
+% \lecture[title={TestingLectureLongOne}, speaker={Heindl}, location={\zoom}, day={T}, time={12:30-13:30}, prio={\phigh}]
+% \hspace*{-.2\textwidth}
+% \end{timetable}
+%
+% \subsection{Calendar related things}
+% Now some environments and commands come which in generally are being used
+% to typeset a table with the detailed information, but which also store
+% the gathered data internally.\\
+% This saved data can be used to output a calendar where the events (from
+% the saved data) are highlighted with a mark (already passed days are
+% crossed and the current day is highlighted as well).
+%
+% The different environments described below are similar in general, but
+% differ in detail (mostly the list of argument that are passed and printed
+% in the table).
+%
+% \newpage
+% \paragraph{Example}\mbox{}\\
+% |\begin{appointments}{true}|\\
+% | \appointment[print=true,shift=false,tikz={fill=black,rectangle},|\\
+% | date={2022-04-15}, course={Appointment with my dog},|\\
+% | end={2022-04-18}, period={1}]|\\
+% | \appointment[date={2022-04-14}, course={Appointment with my dog},|\\
+% | room={at home}, time={12:00}, prio={\pmandatory}]|\\
+% |\end{appointments}|\\
+% |\begin{exams}{false}|\\
+% | \exam[tikz={fill=yellow}, date={2022-06-20}, time={arround midday},|\\
+% | course={Driving}, desc={Mid-Term}, prio={\phigh},|\\
+% | room={University}, type={\oral}]|\\
+% |\end{exams}|\\
+% |\begin{deadlines}{false}|\\
+% | \deadline[tikz={fill=blue}, date={2022-06-22},|\\
+% | course={Submitting Driver-license form}, prio={\phigh}]|\\
+% |\end{deadlines}|\\
+% ||\\
+% |\printSpCalendar[2]{2022-04-01}{2022-07-31}|
+
+% \begin{appointments}{true}
+% \appointment[print=true,shift=false,tikz={fill=black,rectangle}, date={2022-04-15}, course={Appointment with my dog}, end={2022-04-18}, period={1}]
+% \appointment[date={2022-04-14}, course={Appointment with my dog}, room={at home}, time={12:00}, prio={\pmandatory}]
+% \end{appointments}
+% \begin{exams}{false}
+% \exam[tikz={fill=yellow}, date={2022-06-20}, time={arround midday}, course={Driving}, desc={Mid-Term}, prio={\phigh}, room={University}, type={\oral}]
+% \end{exams}
+% \begin{deadlines}{false}
+% \deadline[tikz={fill=blue}, date={2022-06-22}, course={Submitting Driver-license form}, prio={\phigh}]
+% \end{deadlines}
+%
+% \printSpCalendar[2]{2022-04-01}{2022-07-31}
+%
+% \DescribeMacro{\printSpCalendar} |\printSpCalendar[cols]{start_date}{end_date}|\\
+% This is the macro to output such a calendar populated with the gathered
+% events.\\
+% Use the |cols| argument to specify the amount of columns being used
+% (months set side by side).\\
+% |start_date| and |end_date| both have to be specified in the |YYYY-MM-DD|
+% format.
+%
+% \subsubsection{Appointments}
+% \DescribeEnv{appointments} |\begin{appointments}[Room]{true/false}...\end{appointments}|\\
+% Environment to typeset a table of appointments. Stores the data
+% internally to be able to typeset a calendar (with |\printSpCalendar|)
+% with a mark for each event.\\
+% The optional argument is used as header for the |Room| column (maybe for
+% some appointments another title is more suitable).\\
+% The mandatory argument which is |true/false| decides if the internally
+% stored data used to typeset the calendar is being erased before this
+% environment.
+%
+% \DescribeMacro{\appointment} |\appointment[opts]|\\
+% |opts| are optional arguments (enclosed with |{}|) separated with |,|:
+% \begin{description}
+% \item[|date|] Date of the appointment formatted as |YYYY-MM-DD|
+% \item[|course|] Name of the course
+% \item[|room|] Room (only shown in the table)
+% \item[|time|] Time of the event (free text independant of any
+% formatting, only shown in the table)
+% \item[|prio|] priority of the event (shown in the table) (see
+% \ref{icons})
+% \item[|desc|] Description of the event (shown in the table)
+% \item[|end|] upper boundary when the event should stop to repeat (with
+% |period|). Has to be set to make event periodic/repeating.
+% \item[|period|] Set the period of the repeating event.
+% \item[|draw|] |true/false| wether to draw a mark in the calendar
+% \item[|print|] |true/false| wether to display te entry in the
+% appointments table.
+% \item[|shift|] |true/false| wether to shift the mark in the calendar if
+% there is already another event on that date (to be able to see both
+% marks)
+% \item[|tikz|] Free customizable tikz code used for drawing the mark
+% in the calendar. See the documentation at the end for keys that can
+% be used here (all keys in |/cal|). To simply pass arguments to the
+% tikz-node that is being created for the event use |tikz/.append={your arguments}|\\
+% Use e.g. to set the color of the mark via |tikz/.append={green}|
+% \end{description}
+% \subsubsection{Exams}
+% \DescribeEnv{exams} |\begin{exams}{true/false}...\end{exams}|\\
+% Environment to typeset a table of exams. Stores the data
+% internally to be able to typeset a calendar (with |\printSpCalendar|)
+% with a mark for each event.\\
+% The mandatory argument which is |true/false| decides if the internally
+% stored data used to typeset the calendar is being erased before this
+% environment.
+%
+% \DescribeMacro{\exam} |\exam[opts]|\\
+% |opts| are optional arguments (enclosed with |{}|) separated with |,|:
+% \begin{description}
+% \item[|date|] Date of the exam formatted as |YYYY-MM-DD|
+% \item[|course|] Name of the course
+% \item[|room|] Room (only shown in the table)
+% \item[|type|] Type of the exam (see \ref{icons}) (intended:
+% written/oral)
+% \item[|time|] Time of the event (free text independant of any
+% formatting, only shown in the table)
+% \item[|desc|] Description of the event (shown in the table)
+% \item[|draw|] |true/false| wether to draw a mark in the calendar
+% \item[|print|] |true/false| wether to display te entry in the
+% exams table.
+% \item[|shift|] |true/false| wether to shift the mark in the calendar if
+% there is already another event on that date (to be able to see both
+% marks)
+% \item[|tikz|] Free customizable tikz code used for drawing the mark
+% in the calendar. See the documentation at the end for keys that can
+% be used here (all keys in |/cal|). To simply pass arguments to the
+% tikz-node that is being created for the event use |tikz/.append={your arguments}|\\
+% Use e.g. to set the color of the mark via |tikz/.append={green}|
+% \end{description}
+%
+% \subsubsection{Deadlines}
+% \DescribeEnv{deadlines} |\begin{deadlines}{true/false}...\end{deadlines}|\\
+% Environment to typeset a table of deadlines. Stores the data
+% internally to be able to typeset a calendar (with |\printSpCalendar|)
+% with a mark for each event.\\
+% The mandatory argument which is |true/false| decides if the internally
+% stored data used to typeset the calendar is being erased before this
+% environment.
+%
+% \DescribeMacro{\deadline} |\deadline[opts]|\\
+% |opts| are optional arguments (enclosed with |{}|) separated with |,|:
+% \begin{description}
+% \item[|date|] Date of the deadline formatted as |YYYY-MM-DD|
+% \item[|course|] Name of the course
+% \item[|prio|] priority of the event (shown in the table) (see
+% \ref{icons})
+% \item[|desc|] Description of the event (shown in the table)
+% \item[|draw|] |true/false| wether to draw a mark in the calendar
+% \item[|print|] |true/false| wether to display te entry in the
+% deadlines table.
+% \item[|shift|] |true/false| wether to shift the mark in the calendar if
+% there is already another event on that date (to be able to see both
+% marks)
+% \item[|tikz|] Free customizable tikz code used for drawing the mark
+% in the calendar. See the documentation at the end for keys that can
+% be used here (all keys in |/cal|). To simply pass arguments to the
+% tikz-node that is being created for the event use |tikz/.append={your arguments}|\\
+% Use e.g. to set the color of the mark via |tikz/.append={green}|
+% \end{description}
+%
+% \subsection{Icons}\label{icons}
+% This package defines some modified fontawesome icons (they are being
+% encircled with a white circle for better readability).\\
+% \begin{tabular}{rl|rl}
+% |\zoom| & \textcolor{DodgerBlue}{\faCamera} &
+% |\teams| & \textcolor{DodgerBlue}{\faWindows}
+% \\
+% |\BBB| & \textcolor{DodgerBlue}{\faBold} &
+% |\youtube| & \textcolor{DodgerBlue}{\faYoutubePlay}
+% \\\hline
+% |\pmandatory| & \textcolor{red}{\faWarning} &
+% |\phigh| & \textcolor{red}{\faFlag}
+% \\
+% |\pmid| & \textcolor{yellow}{\faFlag} &
+% |\plow| & \textcolor{green}{\faFlag}
+% \\
+% |\pnone| & \textcolor{gray}{\faTimesCircle}
+% \\ \hline
+% |\tbd| & \faQuestion &
+% |\tba| & \faBullhorn
+% \end{tabular}
+%
+%
+%
+% \newpage
+% \section{Implementation}
+% This package uses |semesterplannerLua| as prefix/directory where
+% possible. Since this is not possible for latex macro names, in this
+% occasions |semesterplannerLua@| is used as prefix.
+% \subsection{semesterplannerlua.sty}
+% \subsubsection{Global Stuff}
+% \begin{macrocode}
+%<*package>
+\RequirePackage{tikz}
+\usetikzlibrary{calendar, positioning, shapes.misc, backgrounds}
+\RequirePackage{pgfkeys}
+\RequirePackage{xcolor}
+\RequirePackage{fontawesome}
+\RequirePackage{luapackageloader} % use the default lua path as well
+% \end{macrocode}
+% Define some colors for the course types (can be globally overwritten)
+% \begin{macrocode}
+\definecolor{seminar}{rgb}{1.0, 0.8, 0.0}
+\definecolor{lecture}{rgb}{0.2, 0.7, 1.0}
+\definecolor{tutorial}{rgb}{0.0, 0.8, 0.0}
+\definecolor{meeting}{rgb}{0.8, 0.0, 0.0}
+\definecolor{officehour}{rgb}{0.0, 0.4, 0.6}
+\definecolor{DodgerBlue}{HTML}{1E90FF}
+% \end{macrocode}
+% \begin{macro}{\semesterplannerLua@encircle}
+% This macro puts a circle arround its argument for better readability. In
+% this package this is used for the fontawesome symbols.
+% \begin{macrocode}
+ \newcommand*{\semesterplannerLua@encircle}[1]{
+ \begin{minipage}[b][1em][c]{1.5em}
+ \begin{tikzpicture}
+ \node[fill,circle,inner sep=1pt, color = white] {#1};
+ \end{tikzpicture}
+ \end{minipage}
+ }
+% \end{macrocode}
+% \end{macro}
+% Commands for exams
+% \begin{macro}{\oral}
+% \begin{macrocode}
+\protected\def\oral{\faComment}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\written}
+% \begin{macrocode}
+\protected\def\written{\faPencil}
+% \end{macrocode}
+% \end{macro}
+% Commands for symbols of priority
+% \begin{macro}{\pmandatory}
+% \begin{macrocode}
+ \protected\def\pmandatory{\semesterplannerLua@encircle{\textcolor{red}{\faWarning}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\phigh}
+% \begin{macrocode}
+ \protected\def\phigh{\semesterplannerLua@encircle{\textcolor{red}{\faFlag}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\pmid}
+% \begin{macrocode}
+ \protected\def\pmid{\semesterplannerLua@encircle{\textcolor{yellow}{\faFlag}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\plow}
+% \begin{macrocode}
+ \protected\def\plow{\semesterplannerLua@encircle{\textcolor{green}{\faFlag}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\pnone}
+% \begin{macrocode}
+ \protected\def\pnone{\semesterplannerLua@encircle{\textcolor{gray}{\faTimesCircle}}}
+% \end{macrocode}
+% \end{macro}
+
+% Commands for online platforms.
+% \begin{macro}{\teams}
+% \begin{macrocode}
+ \protected\def\teams{\semesterplannerLua@encircle{\textcolor{DodgerBlue}{\faWindows}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\zoom}
+% \begin{macrocode}
+ \protected\def\zoom{\semesterplannerLua@encircle{\textcolor{DodgerBlue}{\faCamera}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\youtube}
+% \begin{macrocode}
+ \protected\def\youtube{\semesterplannerLua@encircle{\textcolor{red}{\faYoutubePlay}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\BBB}
+% \begin{macrocode}
+ \protected\def\BBB{\semesterplannerLua@encircle{\textcolor{DodgerBlue}{\faBold}}}
+% \end{macrocode}
+% \end{macro}
+
+% Command for "To be determined" and "To be Announced"
+% \begin{macro}{\tbd}
+% \begin{macrocode}
+ \protected\def\tbd{\faQuestion}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\tba}
+% \begin{macrocode}
+ \protected\def\tba{\faBullhorn}
+% \end{macrocode}
+% \end{macro}
+
+
+% Load the lua modules
+% \begin{macrocode}
+\directlua{sp = require("semesterplannerLua_timetable.lua")}
+\directlua{cal = require("semesterplannerLua_calendar.lua")}
+% \end{macrocode}
+% Set all the pgfkeys required for the arguments. To achieve that the
+% defaults are restored every time the environment is used, this is
+% inside the environment definition. This of course disables all
+% possibilities of setting a global default but enables setting local
+% defaults for the events
+% \begin{macrocode}
+ \pgfkeys{
+% \end{macrocode}
+% |/semesterplannerLua| will be the pgf-path used for this package. Here
+% all used keys are set (and initialized with defaults. |timetable/env/|:
+% \begin{description}
+% \item[|days|] is a list of
+% strings representing the header names for the day columns in the
+% timetable (adding Sat and Sun (additional entries) will result in
+% two more columns.
+% \item[|start time|] can be used to set a fixed time where the timetable
+% starts (otherwise this is calculated from the entries) to enable
+% this behaviour this key has to be set to |HH*60 + MM| (easy way
+% is by using |start time/.evaluated={HH*60+MM}|)
+% \item[|end time|] equivalent to |start time|
+% \item[|width|] is
+% the horizontal width of the timetable (not including the column
+% headers on the top) this can be a latex length string or
+% |\textwidth| as well.
+% \item[|length|] is the vertical length of the
+% timetable (not including the clock labels on the side)
+% measured in cm (in future versions this may become measured in
+% pts for better interaction with the LaTeX lengths.
+% \end{description}
+% \begin{macrocode}
+ /semesterplannerLua/timetable/env/.cd,
+ days/.initial={Mon,Thue,Wend,Thur,Fri}, days/.default={Mon,Thue,Wend,Thur,Fri},
+ dayse/.initial={M,T,W,Th,F}, dayse/.default={M,T,W,Th,F},
+ %
+ start time/.initial=, start time/.default=,
+ end time/.initial=, end time/.default=,
+ %
+ width/.initial=\textwidth, width/.default=\textwidth,
+ length/.initial=10, length/.default=10,
+ %
+% \end{macrocode}
+% |timetable/event/|:
+% \begin{description}
+% \item[|content|] is the content of the event (is passed on without any
+% formatting). Since this is passed to lua without modification
+% its value must be an unexpanded string (lua will simply print
+% it so the eventually the string will be evaluated)
+% \item[|time|] is a |HH:MM-HH:MM| string representing start- and
+% end-time of the event. Used in constructing the content as well
+% \item[|day|] is either |M|,|T|,|W|,|Th| or |F| specifying the day on
+% which the event takes place
+% \item[|tikz|] this key allows the user to manually pass options to the
+% node created for this event
+% \item[|scale width|] allows to scale the width of the event to be able
+% to draw overlapping events besides each other. Will usually be a
+% value between |0| and |1|.
+% \item[|offset|] same goal like |scale width| but shifts the event node
+% by the given value to the right. (Given as value between |0| and
+% |1| indicating how many columns the event should be shifted)
+% \item[|textcolor|] foreground color of the content text
+% \item[|title|] title (set in bold by default)
+% \item[|speaker|]
+% \item[|location|]
+% \item[|prio|]
+% \item[|formatter|] this is special
+% \end{description}
+% \begin{macrocode}
+ /semesterplannerLua/timetable/event/.cd,
+ % event arguments
+ content/.initial=, content/.default=,
+ %
+ time/.initial=, time/.default=,
+ day/.initial=, day/.default=,
+ %
+ tikz/.initial=, tikz/.default=,
+ scale width/.initial=1, scale width/.default=1,
+ offset/.initial=0, offset/.default=0,
+ %
+ textcolor/.initial=, textcolor/.default=,
+ title/.initial=, title/.default=,
+ speaker/.initial=, speaker/.default=,
+ location/.initial=, location/.default=,
+ password/.initial=, password/.default=,
+ prio/.initial=, prio/.default=,
+ type/.initial=, type/.default=,
+ formatter/.initial=timetableformatter, formatter/.default=timetableformatter,
+ %
+% \end{macrocode}
+% |calendar/|:
+% \begin{description}
+% \item[|draw|]
+% \item[|room|]
+% \item[|prio|]
+% \item[|course|]
+% \item[|desc|]
+% \item[|start|]
+% \item[|end|]
+% \item[|tikz|]
+% \item[|period|]
+% \item[|shift|]
+% \item[|print|] Only makes sence if the command is suffixed by a |%|
+% otherwise somehow a space gets inserted (eventhough the |%| is
+% inserted from lua as well
+% \end{description}
+% \begin{macrocode}
+ /semesterplannerLua/calendar/.cd,
+ draw/.initial={true}, draw/.default={true},
+ room/.initial={}, room/.default={},
+ time/.initial={}, time/.default={},
+ prio/.initial={}, prio/.default={},
+ course/.initial={}, course/.default={},
+ desc/.initial={}, desc/.default={},
+ type/.initial={}, type/.default={},
+ date/.initial={}, date/.default={},
+ end/.initial={}, end/.default={},
+ tikz/.initial={}, tikz/.default={},
+ period/.initial={nil}, period/.default={nil},
+ shift/.initial={true}, shift/.default={true},
+ print/.initial={true}, print/.default={true},
+ }
+% \end{macrocode}
+%
+% \subsection{Tikz Calendar add weekday labels}
+% \begin{macrocode}
+\tikzoption{day headings}{\tikzstyle{day heading}=[#1]}
+\tikzstyle{day heading}=[]
+\tikzstyle{day letter headings}=[
+ execute before day scope={ \ifdate{day of month=1}{%
+ \pgfmathsetlength{\pgf@ya}{\tikz@lib@cal@yshift}%
+ \pgfmathsetlength\pgf@xa{\tikz@lib@cal@xshift}%
+ \pgftransformyshift{-\pgf@ya}
+ \foreach \d/\l in {0/M,1/T,2/W,3/T,4/F,5/S,6/S} {
+ \pgf@xa=\d\pgf@xa%
+ \pgftransformxshift{\pgf@xa}%
+ \pgftransformyshift{\pgf@ya}%
+ \node[every day,day heading]{\l};%
+ }
+ }{}%
+ }%
+]
+% \end{macrocode}
+%
+% \subsubsection{Local Stuff (timetable-env local)}
+% \begin{environment}{timetable}
+% This is the environment doing all the stuff. To gate the positions where
+% the corresponding macros can be used (and in terms of pgfkeys for reasons
+% of default values) all the macros used are put into the environment.
+% \begin{macrocode}
+\newenvironment{timetable}[1][]{
+ \section*{\faClockO~Timetable}
+% \end{macrocode}
+%
+% Read the argumens given by the user after restoring the defaults
+% (Restoring currently makes no sense, since they are created a few
+% lines above anyways, but creation might be moved outside the
+% environment some day.\\
+% Afterwards the lua module is beeing initialized (erase data from
+% possible previous runs.
+% \begin{macrocode}
+ \pgfkeys{/semesterplannerLua/timetable/env/.cd, days,dayse, start time,end time, width,length, #1}
+ \directlua{sp.init{
+ days=[[\pgfkeysvalueof{/semesterplannerLua/timetable/env/days}]],
+ min=[[\pgfkeysvalueof{/semesterplannerLua/timetable/env/start time}]],
+ max=[[\pgfkeysvalueof{/semesterplannerLua/timetable/env/end time}]],
+ dayse=[[\pgfkeysvalueof{/semesterplannerLua/timetable/env/dayse}]]}}
+% \end{macrocode}
+% \begin{macro}{\semesterplannerLua@event}
+% Is used to pass the event to the lua engine which in turn will collect
+% the event to draw it in the end. For that the arguments given are parsed
+% after restoring the pgf keys to their default values. The optional
+% argument herby is a sequence of pgf keys, the second argument is
+% a string representing the content (this MUST be unexpanded since
+% this is passed to lua which in turn will pass it unmodified back)
+% \begin{macrocode}
+ \newcommand{\semesterplannerLua@event}[1][]{
+ \pgfkeys{/semesterplannerLua/timetable/event/.cd,content,time,day,tikz,scale
+ width,offset,textcolor,title,speaker,type,location,password,prio,formatter, ##1}
+ \directlua{
+ sp.addEvent{
+ time="\pgfkeysvalueof{/semesterplannerLua/timetable/event/time}",
+ day="\pgfkeysvalueof{/semesterplannerLua/timetable/event/day}",
+ tikz=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/tikz}]],
+ offset=\pgfkeysvalueof{/semesterplannerLua/timetable/event/offset},
+ scale_width=\pgfkeysvalueof{/semesterplannerLua/timetable/event/scale width},
+ formatter=\pgfkeysvalueof{/semesterplannerLua/timetable/event/formatter},
+ textcolor=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/textcolor}]],
+ title=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/title}]],
+ speaker=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/speaker}]],
+ location=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/location}]],
+ password=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/password}]],
+ prio=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/prio}]],
+ type=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/type}]],
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% Short-hand macros for different events using the corresponding
+% background color
+%
+% \begin{macro}{\lecture}
+% \begin{macrocode}
+ \newcommand{\lecture}[1][]{
+ \semesterplannerLua@event[tikz={fill=lecture,}, textcolor=white, type=lect, ##1]
+ \ignorespaces
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\seminar}
+% \begin{macrocode}
+ \newcommand{\seminar}[1][]{
+ \semesterplannerLua@event[tikz={fill=seminar,}, textcolor=white, type=sem, ##1]
+ \ignorespaces
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\tutorial}
+% \begin{macrocode}
+ \newcommand{\tutorial}[1][]{
+ \semesterplannerLua@event[tikz={fill=tutorial,}, textcolor=white, type=tut, ##1]
+ \ignorespaces
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\meeting}
+% \begin{macrocode}
+ \newcommand{\meeting}[1][]{
+ \semesterplannerLua@event[tikz={fill=meeting,}, textcolor=white, type=meet, ##1]
+ \ignorespaces
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\officehour}
+% \begin{macrocode}
+ \newcommand{\officehour}[1][]{
+ \semesterplannerLua@event[tikz={fill=officehour,}, textcolor=white, type=office, ##1]
+ \ignorespaces
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+}{
+% \end{macrocode}
+% At the end of the environment after all events have been collected,
+% generate and output the tikz code needed to draw the timetable.
+% \begin{macrocode}
+ \directlua{sp.draw(
+ [[\pgfkeysvalueof{/semesterplannerLua/timetable/env/length}]],
+ [[\pgfkeysvalueof{/semesterplannerLua/timetable/env/width}]])}
+}
+% \end{macrocode}
+% \end{environment}
+%
+% \begin{macrocode}
+
+% \end{macrocode}
+% \begin{macro}{printSpCalendar}
+% Print a calendar from startDate to endDate (encoded as YYYY-MM-DD) as
+% one calendar per month in a matrix with the given amount of columns
+% \begin{macrocode}
+\newcommand{\printSpCalendar}[3][3]{\directlua{cal.drawCalendar("#2", "#3", #1)}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+
+\newenvironment{appointments}[2][Room]{
+ \directlua{cal.init(#2)}
+ \newcommand{\appointment}[1][]{%
+ \pgfkeys{/semesterplannerLua/calendar/.cd,draw,room,time,prio,course,desc,date,end,tikz,period,type,shift,print, ##1}%
+ \directlua{
+ cal.addAppointment{draw=\pgfkeysvalueof{/semesterplannerLua/calendar/draw},
+ room=[[\pgfkeysvalueof{/semesterplannerLua/calendar/room}]],
+ time=[[\pgfkeysvalueof{/semesterplannerLua/calendar/time}]],
+ prio=[[\pgfkeysvalueof{/semesterplannerLua/calendar/prio}]],
+ course=[[\pgfkeysvalueof{/semesterplannerLua/calendar/course}]],
+ desc=[[\pgfkeysvalueof{/semesterplannerLua/calendar/desc}]],
+ date=[[\pgfkeysvalueof{/semesterplannerLua/calendar/date}]],
+ endDate=[[\pgfkeysvalueof{/semesterplannerLua/calendar/end}]],
+ tikz=[[\pgfkeysvalueof{/semesterplannerLua/calendar/tikz}]],
+ period=\pgfkeysvalueof{/semesterplannerLua/calendar/period},
+ shift=\pgfkeysvalueof{/semesterplannerLua/calendar/shift},
+ print=\pgfkeysvalueof{/semesterplannerLua/calendar/print}}}%
+ \ignorespaces
+ }
+ \section*{\faCalendar~Appointments}
+ \begin{tabular}{rlllll}
+ \textbf{Date}&\textbf{Time}&\textbf{Course}&\textbf{Description}&\textbf{#1}&\textbf{Prio.}\\
+}{
+ \end{tabular}
+}
+
+\newenvironment{exams}[1]{
+ \directlua{cal.init(#1)}
+ \newcommand{\exam}[1][]{%
+ \pgfkeys{/semesterplannerLua/calendar/.cd,draw,room,time,prio,course,desc,date,end,tikz,period,type,shift,print, ##1}%
+ \directlua{
+ cal.addExam{
+ draw=\pgfkeysvalueof{/semesterplannerLua/calendar/draw},
+ room=[[\pgfkeysvalueof{/semesterplannerLua/calendar/room}]],
+ time=[[\pgfkeysvalueof{/semesterplannerLua/calendar/time}]],
+ course=[[\pgfkeysvalueof{/semesterplannerLua/calendar/course}]],
+ desc=[[\pgfkeysvalueof{/semesterplannerLua/calendar/desc}]],
+ date=[[\pgfkeysvalueof{/semesterplannerLua/calendar/date}]],
+ tikz=[[\pgfkeysvalueof{/semesterplannerLua/calendar/tikz}]],
+ type=[[\pgfkeysvalueof{/semesterplannerLua/calendar/type}]],
+ shift=\pgfkeysvalueof{/semesterplannerLua/calendar/shift},
+ print=\pgfkeysvalueof{/semesterplannerLua/calendar/print}}}%
+ \ignorespaces
+ }
+ \section*{\faStickyNoteO~Exams}
+ \begin{tabular}{rllll}
+ \textbf{Date}&\textbf{Time}&\textbf{Course}&\textbf{Type}&\textbf{Note}\\
+}{
+ \end{tabular}
+}
+
+\newenvironment{deadlines}[1]{
+ \directlua{cal.init(#1)}
+ \newcommand{\deadline}[1][]{%
+ \pgfkeys{/semesterplannerLua/calendar/.cd,draw,room,time,prio,course,desc,date,end,tikz,period,type,shift,print, ##1}%
+ \directlua{
+ cal.addDeadline{
+ draw=\pgfkeysvalueof{/semesterplannerLua/calendar/draw},
+ course=[[\pgfkeysvalueof{/semesterplannerLua/calendar/course}]],
+ desc=[[\pgfkeysvalueof{/semesterplannerLua/calendar/desc}]],
+ date=[[\pgfkeysvalueof{/semesterplannerLua/calendar/date}]],
+ tikz=[[\pgfkeysvalueof{/semesterplannerLua/calendar/tikz}]],
+ prio=[[\pgfkeysvalueof{/semesterplannerLua/calendar/prio}]],
+ shift=\pgfkeysvalueof{/semesterplannerLua/calendar/shift},
+ print=\pgfkeysvalueof{/semesterplannerLua/calendar/print}}}%
+ \ignorespaces
+ }
+ \section*{\faStickyNoteO~Deadlines}
+ \begin{tabular}{rlll}
+ \textbf{Date}&\textbf{Course}&\textbf{Description}&\textbf{Prio}\\
+}{
+ \end{tabular}
+}
+% \end{macrocode}
+\endinput
+%
+% \iffalse
+%</package>
+% \fi
+%
+% \Finale
+\endinput
diff --git a/Master/texmf-dist/source/lualatex/semesterplannerlua/semesterplannerlua.ins b/Master/texmf-dist/source/lualatex/semesterplannerlua/semesterplannerlua.ins
new file mode 100644
index 00000000000..d6815fbc1bb
--- /dev/null
+++ b/Master/texmf-dist/source/lualatex/semesterplannerlua/semesterplannerlua.ins
@@ -0,0 +1,59 @@
+%% Copyright (C) 2024 by Lukas Heindl <oss.heindl+latex@protonmail.com>
+%% --------------------------------------------------------------------------
+%% 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 2005/12/01 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%%
+%% The Current Maintainer of this work is Lukas Heindl.
+%%
+%% This work consists of the files semesterplannerlua.dtx and semesterplannerlua.ins
+%% and the derived filebase semesterplannerlua.sty.
+%%
+
+\input docstrip.tex
+\keepsilent
+
+\usedir{tex/latex/semesterplannerLua}
+
+\preamble
+
+This is a generated file.
+
+Copyright (C) 2024 by Lukas Heindl <oss.heindl+latex@protonmail.com>
+--------------------------------------------------------------------------
+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 2005/12/01 or later.
+
+\endpreamble
+
+\generate{
+ \file{semesterplannerlua.sty}{\from{semesterplannerlua.dtx}{package}}
+}
+
+\obeyspaces
+\Msg{***********************************************************************}
+\Msg{* *}
+\Msg{* To finish the installation you have to move the following *}
+\Msg{* file into a directory searched by TeX: *}
+\Msg{* *}
+\Msg{* semesterplannerlua.sty *}
+\Msg{* *}
+\Msg{* To produce the documentation run the file semesterplannerlua.dtx *}
+\Msg{* through LaTeX. *}
+\Msg{* *}
+\Msg{* Happy TeXing! *}
+\Msg{* *}
+\Msg{***********************************************************************}
+
+\endbatchfile
diff --git a/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua.sty b/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua.sty
new file mode 100644
index 00000000000..deb287c5b07
--- /dev/null
+++ b/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua.sty
@@ -0,0 +1,256 @@
+%%
+%% This is file `semesterplannerlua.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% semesterplannerlua.dtx (with options: `package')
+%%
+%% This is a generated file.
+%%
+%% Copyright (C) 2024 by Lukas Heindl <oss.heindl+latex@protonmail.com>
+%% --------------------------------------------------------------------------
+%% 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 2005/12/01 or later.
+%%
+\NeedsTeXFormat{LaTeX2e}[1999/12/01]
+\ProvidesPackage{semesterplannerlua}
+ [2024/05/19 v1.1.1 Semesterplanner package in lua with tikz only]
+
+\RequirePackage{tikz}
+\usetikzlibrary{calendar, positioning, shapes.misc, backgrounds}
+\RequirePackage{pgfkeys}
+\RequirePackage{xcolor}
+\RequirePackage{fontawesome}
+\RequirePackage{luapackageloader} % use the default lua path as well
+\definecolor{seminar}{rgb}{1.0, 0.8, 0.0}
+\definecolor{lecture}{rgb}{0.2, 0.7, 1.0}
+\definecolor{tutorial}{rgb}{0.0, 0.8, 0.0}
+\definecolor{meeting}{rgb}{0.8, 0.0, 0.0}
+\definecolor{officehour}{rgb}{0.0, 0.4, 0.6}
+\definecolor{DodgerBlue}{HTML}{1E90FF}
+ \newcommand*{\semesterplannerLua@encircle}[1]{
+ \begin{minipage}[b][1em][c]{1.5em}
+ \begin{tikzpicture}
+ \node[fill,circle,inner sep=1pt, color = white] {#1};
+ \end{tikzpicture}
+ \end{minipage}
+ }
+\protected\def\oral{\faComment}
+\protected\def\written{\faPencil}
+ \protected\def\pmandatory{\semesterplannerLua@encircle{\textcolor{red}{\faWarning}}}
+ \protected\def\phigh{\semesterplannerLua@encircle{\textcolor{red}{\faFlag}}}
+ \protected\def\pmid{\semesterplannerLua@encircle{\textcolor{yellow}{\faFlag}}}
+ \protected\def\plow{\semesterplannerLua@encircle{\textcolor{green}{\faFlag}}}
+ \protected\def\pnone{\semesterplannerLua@encircle{\textcolor{gray}{\faTimesCircle}}}
+
+ \protected\def\teams{\semesterplannerLua@encircle{\textcolor{DodgerBlue}{\faWindows}}}
+ \protected\def\zoom{\semesterplannerLua@encircle{\textcolor{DodgerBlue}{\faCamera}}}
+ \protected\def\youtube{\semesterplannerLua@encircle{\textcolor{red}{\faYoutubePlay}}}
+ \protected\def\BBB{\semesterplannerLua@encircle{\textcolor{DodgerBlue}{\faBold}}}
+
+ \protected\def\tbd{\faQuestion}
+ \protected\def\tba{\faBullhorn}
+
+\directlua{sp = require("semesterplannerLua_timetable.lua")}
+\directlua{cal = require("semesterplannerLua_calendar.lua")}
+ \pgfkeys{
+ /semesterplannerLua/timetable/env/.cd,
+ days/.initial={Mon,Thue,Wend,Thur,Fri}, days/.default={Mon,Thue,Wend,Thur,Fri},
+ dayse/.initial={M,T,W,Th,F}, dayse/.default={M,T,W,Th,F},
+ %
+ start time/.initial=, start time/.default=,
+ end time/.initial=, end time/.default=,
+ %
+ width/.initial=\textwidth, width/.default=\textwidth,
+ length/.initial=10, length/.default=10,
+ %
+ /semesterplannerLua/timetable/event/.cd,
+ % event arguments
+ content/.initial=, content/.default=,
+ %
+ time/.initial=, time/.default=,
+ day/.initial=, day/.default=,
+ %
+ tikz/.initial=, tikz/.default=,
+ scale width/.initial=1, scale width/.default=1,
+ offset/.initial=0, offset/.default=0,
+ %
+ textcolor/.initial=, textcolor/.default=,
+ title/.initial=, title/.default=,
+ speaker/.initial=, speaker/.default=,
+ location/.initial=, location/.default=,
+ password/.initial=, password/.default=,
+ prio/.initial=, prio/.default=,
+ type/.initial=, type/.default=,
+ formatter/.initial=timetableformatter, formatter/.default=timetableformatter,
+ %
+ /semesterplannerLua/calendar/.cd,
+ draw/.initial={true}, draw/.default={true},
+ room/.initial={}, room/.default={},
+ time/.initial={}, time/.default={},
+ prio/.initial={}, prio/.default={},
+ course/.initial={}, course/.default={},
+ desc/.initial={}, desc/.default={},
+ type/.initial={}, type/.default={},
+ date/.initial={}, date/.default={},
+ end/.initial={}, end/.default={},
+ tikz/.initial={}, tikz/.default={},
+ period/.initial={nil}, period/.default={nil},
+ shift/.initial={true}, shift/.default={true},
+ print/.initial={true}, print/.default={true},
+ }
+\tikzoption{day headings}{\tikzstyle{day heading}=[#1]}
+\tikzstyle{day heading}=[]
+\tikzstyle{day letter headings}=[
+ execute before day scope={ \ifdate{day of month=1}{%
+ \pgfmathsetlength{\pgf@ya}{\tikz@lib@cal@yshift}%
+ \pgfmathsetlength\pgf@xa{\tikz@lib@cal@xshift}%
+ \pgftransformyshift{-\pgf@ya}
+ \foreach \d/\l in {0/M,1/T,2/W,3/T,4/F,5/S,6/S} {
+ \pgf@xa=\d\pgf@xa%
+ \pgftransformxshift{\pgf@xa}%
+ \pgftransformyshift{\pgf@ya}%
+ \node[every day,day heading]{\l};%
+ }
+ }{}%
+ }%
+]
+\newenvironment{timetable}[1][]{
+ \section*{\faClockO~Timetable}
+ \pgfkeys{/semesterplannerLua/timetable/env/.cd, days,dayse, start time,end time, width,length, #1}
+ \directlua{sp.init{
+ days=[[\pgfkeysvalueof{/semesterplannerLua/timetable/env/days}]],
+ min=[[\pgfkeysvalueof{/semesterplannerLua/timetable/env/start time}]],
+ max=[[\pgfkeysvalueof{/semesterplannerLua/timetable/env/end time}]],
+ dayse=[[\pgfkeysvalueof{/semesterplannerLua/timetable/env/dayse}]]}}
+ \newcommand{\semesterplannerLua@event}[1][]{
+ \pgfkeys{/semesterplannerLua/timetable/event/.cd,content,time,day,tikz,scale
+ width,offset,textcolor,title,speaker,type,location,password,prio,formatter, ##1}
+ \directlua{
+ sp.addEvent{
+ time="\pgfkeysvalueof{/semesterplannerLua/timetable/event/time}",
+ day="\pgfkeysvalueof{/semesterplannerLua/timetable/event/day}",
+ tikz=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/tikz}]],
+ offset=\pgfkeysvalueof{/semesterplannerLua/timetable/event/offset},
+ scale_width=\pgfkeysvalueof{/semesterplannerLua/timetable/event/scale width},
+ formatter=\pgfkeysvalueof{/semesterplannerLua/timetable/event/formatter},
+ textcolor=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/textcolor}]],
+ title=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/title}]],
+ speaker=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/speaker}]],
+ location=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/location}]],
+ password=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/password}]],
+ prio=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/prio}]],
+ type=[[\pgfkeysvalueof{/semesterplannerLua/timetable/event/type}]],
+ }
+ }
+ }
+ \newcommand{\lecture}[1][]{
+ \semesterplannerLua@event[tikz={fill=lecture,}, textcolor=white, type=lect, ##1]
+ \ignorespaces
+ }
+ \newcommand{\seminar}[1][]{
+ \semesterplannerLua@event[tikz={fill=seminar,}, textcolor=white, type=sem, ##1]
+ \ignorespaces
+ }
+ \newcommand{\tutorial}[1][]{
+ \semesterplannerLua@event[tikz={fill=tutorial,}, textcolor=white, type=tut, ##1]
+ \ignorespaces
+ }
+ \newcommand{\meeting}[1][]{
+ \semesterplannerLua@event[tikz={fill=meeting,}, textcolor=white, type=meet, ##1]
+ \ignorespaces
+ }
+ \newcommand{\officehour}[1][]{
+ \semesterplannerLua@event[tikz={fill=officehour,}, textcolor=white, type=office, ##1]
+ \ignorespaces
+ }
+}{
+ \directlua{sp.draw(
+ [[\pgfkeysvalueof{/semesterplannerLua/timetable/env/length}]],
+ [[\pgfkeysvalueof{/semesterplannerLua/timetable/env/width}]])}
+}
+
+\newcommand{\printSpCalendar}[3][3]{\directlua{cal.drawCalendar("#2", "#3", #1)}}
+
+\newenvironment{appointments}[2][Room]{
+ \directlua{cal.init(#2)}
+ \newcommand{\appointment}[1][]{%
+ \pgfkeys{/semesterplannerLua/calendar/.cd,draw,room,time,prio,course,desc,date,end,tikz,period,type,shift,print, ##1}%
+ \directlua{
+ cal.addAppointment{draw=\pgfkeysvalueof{/semesterplannerLua/calendar/draw},
+ room=[[\pgfkeysvalueof{/semesterplannerLua/calendar/room}]],
+ time=[[\pgfkeysvalueof{/semesterplannerLua/calendar/time}]],
+ prio=[[\pgfkeysvalueof{/semesterplannerLua/calendar/prio}]],
+ course=[[\pgfkeysvalueof{/semesterplannerLua/calendar/course}]],
+ desc=[[\pgfkeysvalueof{/semesterplannerLua/calendar/desc}]],
+ date=[[\pgfkeysvalueof{/semesterplannerLua/calendar/date}]],
+ endDate=[[\pgfkeysvalueof{/semesterplannerLua/calendar/end}]],
+ tikz=[[\pgfkeysvalueof{/semesterplannerLua/calendar/tikz}]],
+ period=\pgfkeysvalueof{/semesterplannerLua/calendar/period},
+ shift=\pgfkeysvalueof{/semesterplannerLua/calendar/shift},
+ print=\pgfkeysvalueof{/semesterplannerLua/calendar/print}}}%
+ \ignorespaces
+ }
+ \section*{\faCalendar~Appointments}
+ \begin{tabular}{rlllll}
+ \textbf{Date}&\textbf{Time}&\textbf{Course}&\textbf{Description}&\textbf{#1}&\textbf{Prio.}\\
+}{
+ \end{tabular}
+}
+
+\newenvironment{exams}[1]{
+ \directlua{cal.init(#1)}
+ \newcommand{\exam}[1][]{%
+ \pgfkeys{/semesterplannerLua/calendar/.cd,draw,room,time,prio,course,desc,date,end,tikz,period,type,shift,print, ##1}%
+ \directlua{
+ cal.addExam{
+ draw=\pgfkeysvalueof{/semesterplannerLua/calendar/draw},
+ room=[[\pgfkeysvalueof{/semesterplannerLua/calendar/room}]],
+ time=[[\pgfkeysvalueof{/semesterplannerLua/calendar/time}]],
+ course=[[\pgfkeysvalueof{/semesterplannerLua/calendar/course}]],
+ desc=[[\pgfkeysvalueof{/semesterplannerLua/calendar/desc}]],
+ date=[[\pgfkeysvalueof{/semesterplannerLua/calendar/date}]],
+ tikz=[[\pgfkeysvalueof{/semesterplannerLua/calendar/tikz}]],
+ type=[[\pgfkeysvalueof{/semesterplannerLua/calendar/type}]],
+ shift=\pgfkeysvalueof{/semesterplannerLua/calendar/shift},
+ print=\pgfkeysvalueof{/semesterplannerLua/calendar/print}}}%
+ \ignorespaces
+ }
+ \section*{\faStickyNoteO~Exams}
+ \begin{tabular}{rllll}
+ \textbf{Date}&\textbf{Time}&\textbf{Course}&\textbf{Type}&\textbf{Note}\\
+}{
+ \end{tabular}
+}
+
+\newenvironment{deadlines}[1]{
+ \directlua{cal.init(#1)}
+ \newcommand{\deadline}[1][]{%
+ \pgfkeys{/semesterplannerLua/calendar/.cd,draw,room,time,prio,course,desc,date,end,tikz,period,type,shift,print, ##1}%
+ \directlua{
+ cal.addDeadline{
+ draw=\pgfkeysvalueof{/semesterplannerLua/calendar/draw},
+ course=[[\pgfkeysvalueof{/semesterplannerLua/calendar/course}]],
+ desc=[[\pgfkeysvalueof{/semesterplannerLua/calendar/desc}]],
+ date=[[\pgfkeysvalueof{/semesterplannerLua/calendar/date}]],
+ tikz=[[\pgfkeysvalueof{/semesterplannerLua/calendar/tikz}]],
+ prio=[[\pgfkeysvalueof{/semesterplannerLua/calendar/prio}]],
+ shift=\pgfkeysvalueof{/semesterplannerLua/calendar/shift},
+ print=\pgfkeysvalueof{/semesterplannerLua/calendar/print}}}%
+ \ignorespaces
+ }
+ \section*{\faStickyNoteO~Deadlines}
+ \begin{tabular}{rlll}
+ \textbf{Date}&\textbf{Course}&\textbf{Description}&\textbf{Prio}\\
+}{
+ \end{tabular}
+}
+\endinput
+%%
+%% End of file `semesterplannerlua.sty'.
diff --git a/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_calendar.lua b/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_calendar.lua
new file mode 100644
index 00000000000..f2fa0e5e32d
--- /dev/null
+++ b/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_calendar.lua
@@ -0,0 +1,132 @@
+local dateLib = require "date"
+function init(clear)
+ -- clean up first
+ -- global variable
+ if clear then
+ EVENTS = {}
+ end
+end
+
+text = {
+ print = function(s)
+ -- print("\"" .. s .. "\"")
+ tex.print(s)
+ end
+}
+
+function genDot(opts)
+ dot = ""
+ if opts.draw then
+ dot = string.format([[\tikz[baseline=(X.base)]\node (X) [fill opacity=.5,fill=red,circle,inner sep=0mm, %s] {\phantom{D}};]], opts.tikz)
+ end
+ return dot
+end
+
+function addEvent(opts)
+ opts.inputlineno = tex.inputlineno
+ -- print(string.format("collecting from line %d", opts.inputlineno))
+ if opts.draw then
+ assert(opts.date ~= nil and opts.tikz ~= nil, "date and tikz has to be given")
+ if opts.endDate == nil or opts.endDate == '' then
+ table.insert(EVENTS, {shift=opts.shift,date=dateLib(opts.date), tikz=opts.tikz, period=opts.period, endDate=nil, inputlineno=opts.inputlineno})
+ else
+ table.insert(EVENTS, {shift=opts.shift,date=dateLib(opts.date), tikz=opts.tikz, period=opts.period, endDate=dateLib(opts.endDate), inputlineno=opts.inputlineno})
+ end
+ end
+end
+
+function addAppointment(opts)
+ addEvent(opts)
+ dot = genDot(opts)
+ if opts.print then
+ tex.sprint(string.format([[\textit{%s} & %s & %s%s & %s & %s & %s\\]], opts.date, opts.time, dot, opts.course, opts.desc, opts.room, opts.prio))
+ else
+ tex.sprint("%")
+ end
+end
+
+function addExam(opts)
+ addEvent(opts)
+ dot = genDot(opts)
+ if opts.print then
+ tex.sprint(string.format([[\textit{%s} & %s & %s%s & %s & %s \\]], opts.date, opts.time, dot, opts.course, opts.type, opts.desc))
+ else
+ tex.sprint("%")
+ end
+end
+
+function addDeadline(opts)
+ addEvent(opts)
+ dot = genDot(opts)
+ if opts.print then
+ tex.sprint(string.format([[\textit{%s} & %s%s & %s & %s \\]], opts.date, dot, opts.course, opts.desc, opts.prio))
+ else
+ tex.sprint("%")
+ end
+end
+
+function drawCalendar(minDate, maxDate, cols)
+ minDate = dateLib(minDate)
+ maxDate = dateLib(maxDate)
+ text.print([[\begin{tikzpicture}[every calendar/.style={day headings=red!50,day letter headings,inner sep=2pt, week list, month label above centered, month text={\textcolor{red}{\%mt} \%y-}, every month/.style={yshift=3ex}}] ]])
+ text.print([[\matrix[column sep=1em, row sep=1em]{]])
+ local i = 1
+ running = true
+ while running do
+ -- derive end from start, then check if maxDate is reached
+ endDate = minDate:copy():addmonths(1):setday(1):adddays(-1)
+ if endDate >= maxDate then
+ endDate = maxDate
+ running = false
+ end
+ text.print(string.format(
+ [[\calendar (%04d-%02d) [dates=%04d-%02d-%02d to %04d-%02d-%02d] if (Sunday) [red] if (Saturday) [red!50!white] if (equals=\year-\month-\day) [nodes={inner sep=.25em,rectangle,line width=1pt,draw}] if (at least=\year-\month-\day) {} else [nodes={strike out, draw}]; ]],
+ minDate:getyear(), minDate:getmonth(), minDate:getyear(), minDate:getmonth(), minDate:getday(), endDate:getyear(), endDate:getmonth(), endDate:getday()))
+
+ minDate:addmonths(1)
+ minDate:setday(1)
+
+ if i % cols == 0 or not running then
+ text.print([[\\]])
+ else
+ text.print([[&]])
+ end
+ i = i + 1
+ end
+ text.print([[ }; ]])
+
+ local usedDates = {}
+ text.print([[\begin{scope}[on background layer] ]])
+ for i,ele in ipairs(EVENTS) do
+ -- print(string.format("Drawing item from line %d", ele.inputlineno))
+ while ele.date <= maxDate and (ele.endDate == nil or ele.date <= ele.endDate) do
+ local xshift = 0
+ if ele.shift then
+ if usedDates[tostring(ele.date)] ~= nil then
+ xshift = math.ceil(usedDates[tostring(ele.date)] / 2)
+ if usedDates[tostring(ele.date)] % 2 == 0 then
+ xshift = -xshift
+ end
+ usedDates[tostring(ele.date)] = usedDates[tostring(ele.date)] + 1
+ else
+ usedDates[tostring(ele.date)] = 1
+ end
+ end
+ text.print(string.format([[\node[xshift=%d mm, fill opacity=.5,fill=red,circle,text width=0ex,inner sep=1.1ex, %s] at (%04d-%02d-%04d-%02d-%02d) {};]],
+ xshift, ele.tikz, ele.date:getyear(), ele.date:getmonth(), ele.date:getyear(), ele.date:getmonth(), ele.date:getday()))
+ if ele.period == nil then break end
+ ele.date:adddays(ele.period)
+ end
+ end
+ text.print([[\end{scope}]])
+ text.print([[\end{tikzpicture}]])
+end
+
+semesterplannerLuaCal = {
+ init = init,
+ addAppointment = addAppointment,
+ addDeadline = addDeadline,
+ addExam = addExam,
+ drawCalendar = drawCalendar,
+}
+return semesterplannerLuaCal
diff --git a/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_dmenu.lua b/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_dmenu.lua
new file mode 100644
index 00000000000..d267d680715
--- /dev/null
+++ b/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_dmenu.lua
@@ -0,0 +1,156 @@
+#!/usr/bin/env texlua
+
+----------------------
+-- HELPER_FUNCTIONS --
+----------------------
+local function check_installed(prog)
+ local r = os.execute("which " .. prog .. "&> /dev/null")
+ return r
+end
+
+local function help()
+ print("Displays a dmenu prompt with the last, current and next events and copies location/url [+password] to the clipboard")
+ print()
+ print("USAGE:")
+ print(string.format("\t%s dataFile [ignoreType ...]", arg[0]))
+ print()
+ print("OPTIONS:")
+ print()
+ print("ARGS:")
+ print(string.format("\t%-12s\t%s", "<dataFile>", "path to the input csv file with 'start', 'end', 'title', 'location', 'password', 'type' headers (not written in the file)"))
+ print(string.format("\t%-12s\t%s", "", "location may contain '\\href{location}{url}' in which casethe two fields are extracted"))
+ print(string.format("\t%-12s\t%s", "<ignoreType>", "entries with that type are ignored"))
+end
+
+local function dur2str(dur)
+ return string.format("%02d:%02d", dur//60, dur%60)
+end
+
+local function contains(t, ele)
+ for _,v in pairs(t) do
+ if v == ele then return true end
+ end
+ return false
+end
+
+-------------------
+-- PREREQUISITES --
+-------------------
+if not check_installed("dmenu") then
+ print("Error: dmenu has to be installed (options -l, -i and -p required, but these are in the default anyway)")
+ os.exit(-1)
+end
+if not check_installed("xsel") then
+ print("Error: xsel has to be installed")
+ os.exit(-1)
+end
+
+if #arg < 1 then
+ print("Error: At least one argument has to be given")
+ print()
+ help()
+ os.exit(-1)
+end
+if arg[1] == "-h" or arg[1] == "--help" then
+ help()
+ os.exit(0)
+end
+
+local type_exclude = {}
+for i=1,#arg do
+ table.insert(type_exclude, arg[i])
+end
+
+-----------
+-- MAIN --
+----------
+
+local maxes = {title=0, location=0, type=0}
+
+local before = {diff=25*60*7}
+local after = {diff=25*60*7}
+
+local c = {}
+
+local current = os.date("*t")
+local today = tonumber(os.date("%u")) - 1
+current.minutes = current.min + (today*24 + current.hour)*60
+
+local inputs = loadfile(arg[1], "t", {})() -- easy loading comes with the disadvantage that arbitrary code which is in that file gets executed
+for _,ele in ipairs(inputs) do
+ if not contains(type_exclude, ele["type"]) then
+ ele.start, ele["end"] = tonumber(ele.start), tonumber(ele["end"])
+ ele.url = ele.location:match([[\href ?{(.*)}{.*}]])
+ ele.location = ele.location:match([[\href ?{.*}{(.*)}]]) or ele.location
+
+ if maxes.title < #ele.title then maxes.title = #ele.title end
+ if maxes.location < #ele.location then maxes.location = #ele.location end
+ if maxes.type < #ele.type then maxes.type = #ele.type end
+
+ if current.minutes > ele.start and current.minutes < ele["end"] then
+ ele.diff = current.minutes-ele["start"]
+ table.insert(c, ele)
+ elseif current.minutes < ele.start then
+ if ele.start - current.minutes < before.diff then
+ before = {diff=ele.start-current.minutes}
+ end
+ if ele.start - current.minutes <= before.diff then
+ ele.diff = before.diff
+ table.insert(before, ele)
+ end
+ elseif current.minutes > ele["end"] then
+ if current.minutes - ele["end"] < after.diff then
+ after = {diff=current.minutes-ele["end"]}
+ end
+ if current.minutes - ele["end"] <= after.diff then
+ ele.diff = after.diff
+ table.insert(after, ele)
+ end
+ end
+ end
+end
+
+maxes = {title=maxes.title < 100 and maxes.title or 99, location=maxes.location < 100 and maxes.location or 99, type=maxes.type < 100 and maxes.type or 99}
+
+local dmenu_in,map = {},{}
+for _,x in ipairs(after) do
+ local s = string.format("%-".. maxes.title+1+maxes.type .."s %-".. maxes.location+2 .."s # ended %s ago", x.title.."-"..x.type, "("..x.location..")", dur2str(x.diff))
+ table.insert(dmenu_in, s)
+ map[s] = x
+end
+
+for _,x in ipairs(c) do
+ local s = string.format("%-".. maxes.title+1+maxes.type .."s %-".. maxes.location+2 .."s # began %s ago", x.title.."-"..x.type, "("..x.location..")", dur2str(x.diff))
+ table.insert(dmenu_in, s)
+ map[s] = x
+end
+
+for _,x in ipairs(before) do
+ local s = string.format("%-".. maxes.title+1+maxes.type .."s %-".. maxes.location+2 .."s # begins in %s", x.title.."-"..x.type, "("..x.location..")", dur2str(x.diff))
+ table.insert(dmenu_in, s)
+ map[s] = x
+end
+
+local dmenu_ins = table.concat(dmenu_in, "\n")
+
+print(dmenu_ins)
+-- TODO check for forbidden strings in dmenu_in
+local proc = io.popen(string.format("echo '%s' | dmenu -i -l %d -p 'Select entry'", dmenu_ins, #dmenu_in), "r")
+local dmenu_out = proc:read("l")
+if not dmenu_out then
+ os.execute("notify-send 'Uni' 'Nothing selected'")
+ os.exit()
+end
+
+local sel = map[dmenu_out]
+assert(sel, "Error building/reading the lookup table")
+if sel.url and sel.url ~= "" then
+ os.execute(string.format("echo -n '%s' | xsel -b && notify-send -h string:x-canonical-private-synchronous:uni 'Uni' 'Copied URL to clipboard'", sel.url))
+elseif sel.location and sel.location ~= "" then
+ os.execute(string.format("echo -n '%s' | xsel -b && notify-send -h -- string:x-canonical-private-synchronous:uni 'Uni' 'Copied URL to clipboard'", sel.location))
+ os.execute(string.format("echo -n 'https://portal.mytum.de/campus/roomfinder/search_room_results?searchstring=%s&building=Alle&search=Suche+starten' | xsel -b && notify-send -h string:x-canonical-private-synchronous:uni 'Uni' 'Copied Roomfinder-url to clipboard'", sel.location))
+end
+
+if sel.password and sel.password ~= "" then
+ os.execute(string.format("sleep 3 && echo -n '%s' | xsel -b && notify-send -h string:x-canonical-private-synchronous:uni 'Uni' 'Copied password to clipboard'", sel.password))
+end
diff --git a/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_timetable.lua b/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_timetable.lua
new file mode 100644
index 00000000000..049644d2914
--- /dev/null
+++ b/Master/texmf-dist/tex/lualatex/semesterplannerlua/semesterplannerlua_timetable.lua
@@ -0,0 +1,233 @@
+function init(opts)
+ tex.print([[\newwrite\timetableATdataOutput \immediate\openout\timetableATdataOutput=\jobname-data.dat]])
+ tex.print([[\immediate\write\timetableATdataOutput{return \iftrue\string{\else}\fi}]])
+ if(not checkKeys(opts, {"days", "min", "max", "dayse"})) then
+ error("missing argument")
+ end
+ -- clean up first
+ -- global variables
+ EVENTS={}
+ DAYS = prepareDays(opts.days) -- header with names of the days set from tex currently
+ DAYSE = prepareDays(opts.dayse) -- day representation in source code
+ MIN = 25*60 -- bigger than any allowed value could be
+ MAX = 0
+ MIN_BYPASS = false -- weather min is fixed by the user
+ MAX_BYPASS = false -- weather max is fixed by the user
+
+ if(opts.min == "") then
+ else
+ assert(opts.min:match("^%d+"), "start time has to be an integer representing the HH*60+MM of the desired start time")
+ MIN = tonumber(opts.min)
+ MIN_BYPASS = true
+ end
+
+ if(opts.max == "") then
+ else
+ assert(opts.max:match("^%d+"), "end time has to be an integer representing the HH*60+MM of the desired end time")
+ MAX = tonumber(opts.max)
+ MAX_BYPASS = true
+ end
+end
+
+function defaultFormatter(opts)
+ local ret = ""
+ for k,v in pairs(opts) do
+ if type(k) == "string" then k = k:gsub("[_^]", "") end
+ if type(v) == "string" then v = v:gsub("[_^]", "") end
+ ret = string.format("%s, %s: %s", ret, tostring(k), tostring(v))
+ end
+ -- print(ret)
+ return ret
+end
+
+function timetableformatter(opts)
+ return string.format(
+ [[\textcolor{%s}{\textbf{%s}\\[.2em]\raggedright{%s}\\[0.5em]\raggedright{%s}\hfil\raggedright{%s}\\[0.5em]\raggedright{%s}}]],
+ opts.textcolor, opts.title, opts.speaker, opts.prio, opts.location, opts.time)
+end
+-- result are the global variables EVENTS, MIN and MAX
+function addEvent(opts)
+ -- print("Reading event on line ", tex.inputlineno)
+ opts.inputlineno = tex.inputlineno
+ if(not checkKeys(opts, {"time", "day", "tikz"})) then
+ error("missing argument")
+ end
+
+ if opts.content == nil then
+ if opts.formatter == nil then
+ opts.content = defaultFormatter(opts)
+ else
+ opts.content = opts.formatter(opts)
+ end
+ end
+
+ opts.from,opts.to = dur2Int(opts.time)
+
+ tex.print(string.format(
+ [[\immediate\write\timetableATdataOutput{\unexpanded{{["start"]=%q, ["end"]=%q, ["title"]=%q, ["location"]=%q, ["password"]=%q, ["type"]=%q},}}]],
+ opts.from + 24*60*day2Int(opts.day),
+ opts.to + 24*60*day2Int(opts.day),
+ opts.title,
+ opts.location:match([[\href{(.*)}{.*}]]) or opts.location,
+ opts.password,
+ opts.type
+ ))
+
+ if(not MIN_BYPASS and opts.from < MIN) then MIN = opts.from end
+ if(not MAX_BYPASS and opts.to > MAX) then MAX = opts.to end
+ assert(opts.from < opts.to, "From has to be before to")
+
+ table.insert(EVENTS, opts)
+end
+-- parameters are all global variables
+function draw(length, width)
+ -- copy relevant variables for working on local copies
+ local events = copy_array(EVENTS)
+ local days = copy_array(DAYS)
+ local min, minH, max, maxH = prepareMinMax(MIN, MAX)
+
+ assert(length:match("%d*%.?%d*"), "Length must be a valid length measured in cm")
+ length = tonumber(length)
+
+ textwidth = width
+
+ tex.print([[\begin{tikzpicture}]])
+ tex.print([[\tikzset{defStyle/.style={font=\tiny,anchor=north west,fill=blue!50,draw=black,rectangle}}]])
+ -- print the tabular with the weekday headers
+ tex.print(string.format(
+ [[\foreach \week [count=\x from 0, evaluate=\x as \y using \x+0.5] in {%s}{ ]],
+ table.concat(days, ",")
+ )
+ )
+ tex.print(string.format(
+ [[\node[anchor=south] at (\y/%d* %s, 0) {\week};]], #days, textwidth))
+ tex.print(string.format(
+ [[\draw (\x/%d * %s, 0cm) -- (\x/%d * %s, %dcm);]],
+ #days,
+ textwidth,
+ #days,
+ textwidth, -length
+ )
+ )
+ tex.print("}")
+ tex.print(string.format(
+ [[\draw (%s, 0) -- (%s,%dcm);]],
+ textwidth,
+ textwidth,
+ -length
+ )
+ )
+
+ for i=minH,maxH do
+ tex.print(string.format(
+ [[\node[anchor=east] at (0,%fcm ) {%d:00};]],
+ minuteToFrac(i*60,min,max)*-length, i
+ )
+ )
+ tex.print(string.format(
+ [[\draw (0,%fcm ) -- (%s,%fcm );]],
+ minuteToFrac(i*60,min,max)*-length,
+ textwidth,
+ minuteToFrac(i*60,min,max)*-length
+ )
+ )
+ end
+
+ local d
+ local red = 0.3333 -- calculated in em from inner sep
+ local red_y = 0.25 -- calculated in em
+ for _,e in ipairs(events) do
+ if e.from < max and e.to > min then -- only draw if event is in scope (part of the comp is done in addEvent from < to
+ if e.to > max then e.to = max end
+ if e.from < min then e.from = min end
+ -- print("Drawing event on line ", e.inputlineno)
+ d = day2Int(e.day)
+ tex.print(string.format(
+ [[\node[defStyle,text width=-%fem+%f%s/%d, text depth=%fcm-%fem, text height=%fem, %s] at (%f*%s,%fcm) {%s};]],
+ 2*red, -- text width
+ e.scale_width, -- text width
+ textwidth,
+ #days, -- text width
+ length*(e.to-e.from)/(max-min), -- text depth
+ 2*red+red_y, -- text depth
+ red_y, -- text height
+ e.tikz, -- free tikz code
+ (d+e.offset)/#days, -- xcoord
+ textwidth,
+ minuteToFrac(e.from,min,max)*-length, -- ycoord
+ e.content -- content
+ )
+ )
+ end
+ end
+ tex.print([[\end{tikzpicture}]])
+ tex.print([[\immediate\write\timetableATdataOutput{\iffalse{\else\string}\fi}]])
+end
+function search_array(t, s)
+ for k,v in ipairs(t) do
+ if(v == s) then return k end
+ end
+ return nil
+end
+
+function minuteToFrac(minute, min, max)
+ return (minute-min)/(max-min)
+end
+function prepareMinMax(min, max)
+ local minH = math.floor(min/60)
+ local maxH = math.ceil(max/60)
+ local min = minH*60
+ local max = maxH*60
+ return min, minH, max, maxH
+end
+function checkKeys(t, k)
+ for _,x in ipairs(k) do
+ if(t[x] == nil) then
+ return false
+ end
+ end
+ return true
+end
+function dur2Int(clk)
+ local f1,f2, t1,t2 = clk:match("^(%d%d?):(%d%d)-(%d%d?):(%d%d)$")
+ if(f1 ~= nil and f2 ~= nil and t1 ~= nil and t2 ~= nil) then
+ f1 = tonumber(f1) f2 = tonumber(f2)
+ t1 = tonumber(t1) t2 = tonumber(t2)
+ assert(f1 >= 0 and f1 < 24, "Hours have to be >= 0 && < 24")
+ assert(f2 >= 0 and f2 < 60, "Mins have to be >= 0 && < 60")
+ assert(t1 >= 0 and t1 < 24, "Hours have to be >= 0 && < 24")
+ assert(t2 >= 0 and t2 < 60, "Mins have to be >= 0 && < 60")
+ return f1*60 + f2, t1*60 + t2
+ else
+ error("clk string \"" .. clk .. "\" was no valid clock string")
+ end
+end
+function prepareDays(days)
+ local ret = {}
+ for m in days:gmatch("[^,]+") do
+ table.insert(ret, m)
+ end
+ return ret
+end
+function day2Int(day)
+ return search_array(DAYSE, day) - 1
+end
+
+function copy_array(obj)
+ if type(obj) ~= 'table' then return obj end
+ local res = {}
+ for k, v in pairs(obj) do
+ local c = copy_array(v)
+ res[copy_array(k)] = c
+ end
+ return res
+end
+
+semesterplannerLua = {
+ init = init,
+ addEvent = addEvent,
+ draw = draw,
+ day2Int = day2Int,
+}
+return semesterplannerLua
+
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index 2d2445a6c1a..5df68729d83 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -757,7 +757,7 @@ my @TLP_working = qw(
sdaps sdrt sduthesis
se2thesis secdot secnum section sectionbox sectionbreak sectsty seealso
selectp selinput selnolig semantex semantic semantic-markup semaphor
- semesterplanner seminar semioneside semproc semtex
+ semesterplanner semesterplannerlua seminar semioneside semproc semtex
sepfootnotes sepnum seqsplit
serbian-apostrophe serbian-date-lat serbian-def-cyr serbian-lig
sesamanuel sesstime setdeck setspace setspaceenhanced
diff --git a/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc b/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
index 11985b7be56..7cf9d21872f 100644
--- a/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
@@ -98,6 +98,7 @@ depend plantuml
depend pyluatex
depend scikgtex
depend selnolig
+depend semesterplannerlua
depend showhyphenation
depend showkerning
depend spacekern
diff --git a/Master/tlpkg/tlpsrc/semesterplannerlua.tlpsrc b/Master/tlpkg/tlpsrc/semesterplannerlua.tlpsrc
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/semesterplannerlua.tlpsrc