summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Build/source/texk/texlive/linked_scripts/Makefile.am1
-rw-r--r--Build/source/texk/texlive/linked_scripts/Makefile.in1
-rw-r--r--Build/source/texk/texlive/linked_scripts/scripts.lst5
-rwxr-xr-xBuild/source/texk/texlive/linked_scripts/texlive/tlmgr.pl10
-rw-r--r--Build/source/texk/texlive/linked_scripts/texplate/texplate.sh17
l---------Master/bin/aarch64-linux/texplate1
l---------Master/bin/amd64-freebsd/texplate1
l---------Master/bin/amd64-netbsd/texplate1
l---------Master/bin/armhf-linux/texplate1
l---------Master/bin/i386-cygwin/texplate1
l---------Master/bin/i386-freebsd/texplate1
l---------Master/bin/i386-linux/texplate1
l---------Master/bin/i386-netbsd/texplate1
l---------Master/bin/i386-solaris/texplate1
-rwxr-xr-xMaster/bin/win32/texplate.exebin0 -> 1536 bytes
l---------Master/bin/x86_64-cygwin/texplate1
l---------Master/bin/x86_64-darwin/texplate1
l---------Master/bin/x86_64-darwinlegacy/texplate1
l---------Master/bin/x86_64-linux/texplate1
l---------Master/bin/x86_64-linuxmusl/texplate1
l---------Master/bin/x86_64-solaris/texplate1
-rw-r--r--Master/texmf-dist/doc/support/texplate/README.md169
-rw-r--r--Master/texmf-dist/doc/support/texplate/texplate-manual.pdfbin0 -> 103717 bytes
-rw-r--r--Master/texmf-dist/doc/support/texplate/texplate-manual.tex604
-rw-r--r--Master/texmf-dist/scripts/texplate/templates/texplate-article.toml54
-rw-r--r--Master/texmf-dist/scripts/texplate/templates/texplate-standalone.toml45
-rw-r--r--Master/texmf-dist/scripts/texplate/texplate.jarbin0 -> 2815236 bytes
-rw-r--r--Master/texmf-dist/scripts/texplate/texplate.sh17
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/Main.java36
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/InvalidKeySetException.java37
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/InvalidTemplateException.java34
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/TemplateMergingException.java37
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Configuration.java150
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Template.java252
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/TemplateProcessing.java391
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/BooleanHandler.java26
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/CSVListHandler.java30
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/Handler.java20
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/HandlerUtils.java31
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/MergingUtils.java186
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/MessageUtils.java84
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/PathUtils.java129
-rw-r--r--Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/ValidatorUtils.java75
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check6
-rwxr-xr-xMaster/tlpkg/libexec/ctan2tds5
-rw-r--r--Master/tlpkg/tlpsrc/collection-binextra.tlpsrc5
-rw-r--r--Master/tlpkg/tlpsrc/texplate.tlpsrc2
47 files changed, 2464 insertions, 10 deletions
diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.am b/Build/source/texk/texlive/linked_scripts/Makefile.am
index 22b1a3ba880..20cc60e497d 100644
--- a/Build/source/texk/texlive/linked_scripts/Makefile.am
+++ b/Build/source/texk/texlive/linked_scripts/Makefile.am
@@ -206,6 +206,7 @@ texmf_other_scripts = \
texlive/updmap.pl \
texliveonfly/texliveonfly.py \
texloganalyser/texloganalyser \
+ texplate/texplate.sh \
thumbpdf/thumbpdf.pl \
tlcockpit/tlcockpit.sh \
tlshell/tlshell.tcl \
diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.in b/Build/source/texk/texlive/linked_scripts/Makefile.in
index 62893dcfce9..2638631a1c7 100644
--- a/Build/source/texk/texlive/linked_scripts/Makefile.in
+++ b/Build/source/texk/texlive/linked_scripts/Makefile.in
@@ -419,6 +419,7 @@ texmf_other_scripts = \
texlive/updmap.pl \
texliveonfly/texliveonfly.py \
texloganalyser/texloganalyser \
+ texplate/texplate.sh \
thumbpdf/thumbpdf.pl \
tlcockpit/tlcockpit.sh \
tlshell/tlshell.tcl \
diff --git a/Build/source/texk/texlive/linked_scripts/scripts.lst b/Build/source/texk/texlive/linked_scripts/scripts.lst
index 9aa442a4d85..b7861c5f665 100644
--- a/Build/source/texk/texlive/linked_scripts/scripts.lst
+++ b/Build/source/texk/texlive/linked_scripts/scripts.lst
@@ -138,6 +138,10 @@ texfot/texfot.pl
texlive/fmtutil-sys.sh
texlive/fmtutil-user.sh
texlive/fmtutil.pl
+texlive/mktexlsr
+texlive/mktexmf
+texlive/mktexpk
+texlive/mktextfm
texlive/rungs.tlu
texlive/tlmgr.pl
texlive/updmap-sys.sh
@@ -145,6 +149,7 @@ texlive/updmap-user.sh
texlive/updmap.pl
texliveonfly/texliveonfly.py
texloganalyser/texloganalyser
+texplate/texplate.sh
thumbpdf/thumbpdf.pl
tlcockpit/tlcockpit.sh
tlshell/tlshell.tcl
diff --git a/Build/source/texk/texlive/linked_scripts/texlive/tlmgr.pl b/Build/source/texk/texlive/linked_scripts/texlive/tlmgr.pl
index 71fd28e5b7a..2dd7ecb275b 100755
--- a/Build/source/texk/texlive/linked_scripts/texlive/tlmgr.pl
+++ b/Build/source/texk/texlive/linked_scripts/texlive/tlmgr.pl
@@ -1,12 +1,12 @@
#!/usr/bin/env perl
-# $Id: tlmgr.pl 53225 2019-12-24 19:19:02Z karl $
+# $Id: tlmgr.pl 53428 2020-01-16 23:29:27Z karl $
#
-# Copyright 2008-2019 Norbert Preining
+# Copyright 2008-2020 Norbert Preining
# This file is licensed under the GNU General Public License version 2
# or any later version.
-my $svnrev = '$Revision: 53225 $';
-my $datrev = '$Date: 2019-12-24 20:19:02 +0100 (Tue, 24 Dec 2019) $';
+my $svnrev = '$Revision: 53428 $';
+my $datrev = '$Date: 2020-01-17 00:29:27 +0100 (Fri, 17 Jan 2020) $';
my $tlmgrrevision;
my $tlmgrversion;
my $prg;
@@ -10008,7 +10008,7 @@ This script and its documentation were written for the TeX Live
distribution (L<https://tug.org/texlive>) and both are licensed under the
GNU General Public License Version 2 or later.
-$Id: tlmgr.pl 53225 2019-12-24 19:19:02Z karl $
+$Id: tlmgr.pl 53428 2020-01-16 23:29:27Z karl $
=cut
# test HTML version: pod2html --cachedir=/tmp tlmgr.pl >/tmp/tlmgr.html
diff --git a/Build/source/texk/texlive/linked_scripts/texplate/texplate.sh b/Build/source/texk/texlive/linked_scripts/texplate/texplate.sh
new file mode 100644
index 00000000000..da649780378
--- /dev/null
+++ b/Build/source/texk/texlive/linked_scripts/texplate/texplate.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Public domain. Originally written by Norbert Preining and Karl Berry, 2018.
+# Note from Paulo: this script provides better Cygwin support than our original
+# approach, so the team decided to use it as a proper wrapper for texplate as well.
+
+scriptname=`basename "$0"`
+jar="$scriptname.jar"
+jarpath=`kpsewhich --progname="$scriptname" --format=texmfscripts "$jar"`
+
+kernel=`uname -s 2>/dev/null`
+if echo "$kernel" | grep CYGWIN >/dev/null; then
+ CYGWIN_ROOT=`cygpath -w /`
+ export CYGWIN_ROOT
+ jarpath=`cygpath -w "$jarpath"`
+fi
+
+exec java -jar "$jarpath" "$@" \ No newline at end of file
diff --git a/Master/bin/aarch64-linux/texplate b/Master/bin/aarch64-linux/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/aarch64-linux/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/amd64-freebsd/texplate b/Master/bin/amd64-freebsd/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/amd64-freebsd/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/amd64-netbsd/texplate b/Master/bin/amd64-netbsd/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/amd64-netbsd/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/armhf-linux/texplate b/Master/bin/armhf-linux/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/armhf-linux/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/i386-cygwin/texplate b/Master/bin/i386-cygwin/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/i386-cygwin/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/i386-freebsd/texplate b/Master/bin/i386-freebsd/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/i386-freebsd/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/i386-linux/texplate b/Master/bin/i386-linux/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/i386-linux/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/i386-netbsd/texplate b/Master/bin/i386-netbsd/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/i386-netbsd/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/i386-solaris/texplate b/Master/bin/i386-solaris/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/i386-solaris/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/win32/texplate.exe b/Master/bin/win32/texplate.exe
new file mode 100755
index 00000000000..5777d90a17a
--- /dev/null
+++ b/Master/bin/win32/texplate.exe
Binary files differ
diff --git a/Master/bin/x86_64-cygwin/texplate b/Master/bin/x86_64-cygwin/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/x86_64-cygwin/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/x86_64-darwin/texplate b/Master/bin/x86_64-darwin/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/x86_64-darwin/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/x86_64-darwinlegacy/texplate b/Master/bin/x86_64-darwinlegacy/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/x86_64-darwinlegacy/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/x86_64-linux/texplate b/Master/bin/x86_64-linux/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/x86_64-linux/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/x86_64-linuxmusl/texplate b/Master/bin/x86_64-linuxmusl/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/x86_64-linuxmusl/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/bin/x86_64-solaris/texplate b/Master/bin/x86_64-solaris/texplate
new file mode 120000
index 00000000000..74cffe9f69c
--- /dev/null
+++ b/Master/bin/x86_64-solaris/texplate
@@ -0,0 +1 @@
+../../texmf-dist/scripts/texplate/texplate.sh \ No newline at end of file
diff --git a/Master/texmf-dist/doc/support/texplate/README.md b/Master/texmf-dist/doc/support/texplate/README.md
new file mode 100644
index 00000000000..7fea81da09e
--- /dev/null
+++ b/Master/texmf-dist/doc/support/texplate/README.md
@@ -0,0 +1,169 @@
+# TeXplate
+
+![Language: Kotlin](https://img.shields.io/badge/Language-Kotlin-blue.svg?style=flat-square) ![Minimum JRE: 8.0](https://img.shields.io/badge/Minimum_JRE-8.0-blue.svg?style=flat-square) ![Current version: 1.0.1](https://img.shields.io/badge/Current_version-1.0.1-blue.svg?style=flat-square)
+
+TeXplate is a tool for creating document structures based on templates. The application name is a word play on _TeX_ and _template_, so the purpose seems quite obvious: we want to provide an easy and straightforward framework for reducing the typical code boilerplate when writing TeX documents. Also note that one can easily extrapolate the use beyond articles and theses: the application is powerful enough to generate _any_ text-based structure, given that a corresponding template exists.
+
+## Basic use
+
+Our tool is a typical command line application, so we need to invoke it by simply typing `texplate` in the terminal:
+
+```bash
+$ texplate
+ ______ __ __ ___ __
+/\__ _\ /\ \ /\ \ /\_ \ /\ \__
+\/_/\ \/ __ \ `\`\/'/' _____\//\ \ __ \ \ ,_\ __
+ \ \ \ /'__`\`\/ > < /\ '__`\\ \ \ /'__`\ \ \ \/ /'__`\
+ \ \ \/\ __/ \/'/\`\\ \ \L\ \\_\ \_/\ \L\.\_\ \ \_/\ __/
+ \ \_\ \____\ /\_\\ \_\ \ ,__//\____\ \__/.\_\\ \__\ \____\
+ \/_/\/____/ \/_/ \/_/\ \ \/ \/____/\/__/\/_/ \/__/\/____/
+ \ \_\
+ \/_/
+
+TeXplate 1.0.1, a document structure creation tool
+Copyright (c) 2020, Island of TeX
+All rights reserved.
+
+Missing required option '--output=<output>'
+Usage: texplate [-c=<configuration>] -o=<output> [-t=<template>]
+ [-m=<String=String>...]...
+ -c, --config=<configuration>
+ The configuration file in which the tool
+ can read template data, for automation
+ purposes. Make sure to follow the correct
+ specification when writing a
+ configuration file.
+ -m, --map=<String=String>...
+ The contextual map that provides the data
+ to be merged in the template. This
+ parameter can be used multiple times. You
+ can specify a map entry with the
+ key=value syntax (mind the entry
+ separator).
+ -o, --output=<output> The output file in which the chosen
+ template will be effectively written.
+ Make sure the directory has the correct
+ permissions for writing the output file.
+ -t, --template=<template>
+ The template and. The tool will search both
+ user and system locations and set the
+ template model accordingly, based on your
+ specs.
+```
+
+
+
+Provided that TeXplate is properly available in the underlying operating system, we will get a lovely, colorful output in our terminal, along with a couple of scary messages telling that some required options are missing. Our tool provides four options, described as follows. Strictly speaking, there is only one mandatory option. The remainder might be optional, depending on certain scenarios.
+
+### Output
+
+Referred as either`-o` (short representation) or `--output` (long representation), this option holds the output file in which the chosen template will be effectively written. The name is arbitrary, so you can use anything to your heart's desires. Keep in mind, however, that an existing file will be mercilessly overwritten. Also, make sure the path has the proper permissions for writing the output file.
+
+### Template
+
+Referred as either `-t` (short representation) or `--template` (long representation), this option holds the reference to the template to be potentially merged with data and properly generated. The provided string should match the template identifier, otherwise TeXplate will raise an error complaining about the missing reference.
+
+### Map
+
+Referred as either `-m` (short representation) or `--map` (long representation), this option holds a map entry, defined as a `key=value` ordered pair (mind the `=` symbol used as entry separator). This option can be used multiple times. The map entry denotes a variable in the template context, where the key is the variable name and the value is set to be the initial state of such variable.
+
+## Examples
+
+For instance, let us generate a document named `doc1.tex`, based on the standard `article` class:
+
+```bash
+$ texplate -t article -o doc1.tex
+ ______ __ __ ___ __
+/\__ _\ /\ \ /\ \ /\_ \ /\ \__
+\/_/\ \/ __ \ `\`\/'/' _____\//\ \ __ \ \ ,_\ __
+ \ \ \ /'__`\`\/ > < /\ '__`\\ \ \ /'__`\ \ \ \/ /'__`\
+ \ \ \/\ __/ \/'/\`\\ \ \L\ \\_\ \_/\ \L\.\_\ \ \_/\ __/
+ \ \_\ \____\ /\_\\ \_\ \ ,__//\____\ \__/.\_\\ \__\ \____\
+ \/_/\/____/ \/_/ \/_/\ \ \/ \/____/\/__/\/_/ \/__/\/____/
+ \ \_\
+ \/_/
+
+TeXplate 1.0.1, a document structure creation tool
+Copyright (c) 2020, Island of TeX
+All rights reserved.
+
+Configuration file mode disabled .................. [ DONE ]
+Entering full command line mode ................... [ DONE ]
+
+Please, wait...
+
+Obtaining reference ............................... [ DONE ]
+Composing template ................................ [ DONE ]
+Validating data ................................... [ DONE ]
+Merging template and data ......................... [ DONE ]
+
+Done! Enjoy your template!
+Written: 112 B
+```
+
+And that is it! We provided the template name (`-t article`) and the output (`-o doc1.tex`). Checking the contents of `doc1.tex`:
+
+```tex
+\documentclass{article}
+
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+
+\begin{document}
+
+\end{document}
+```
+
+We could enhance the template generation by providing further options to it. Let us say we want to include A4 as the paper size for our document and use XeTeX as engine. The command line is as follows (we omitted the full output for reducing verbosity):
+
+```bash
+$ texplate -t article -o doc2.tex -m options=a4paper -m xetex=true
+```
+
+For this example, we added two map entries referring to the class option and the support for newer engines (please refer to the user manual for more details on template options). The newly generated `doc2.tex` document is as follows:
+
+```tex
+\documentclass[a4paper]{article}
+
+\usepackage{fontspec}
+
+\begin{document}
+
+\end{document}
+```
+
+Now, let us provide some packages to our document, as well as language support:
+
+```bash
+$ texplate -t article -o doc3.tex -m options=a4paper -m xetex=true \
+-m babel=spanish,english -m packages=longtable,siunitx,array
+```
+
+Checking the contents of `doc3.tex`:
+
+```tex
+\documentclass[a4paper]{article}
+
+\usepackage{fontspec}
+
+\usepackage[spanish,english]{babel}
+
+\usepackage{longtable}
+\usepackage{siunitx}
+\usepackage{array}
+
+\begin{document}
+
+\end{document}
+```
+
+And that is it! Make sure to take a look at the user manual to learn more about TeXplate!
+
+## License
+
+This application is licensed under the [New BSD License](https://opensource.org/licenses/BSD-3-Clause). Please note that the New BSD License has been verified as a GPL-compatible free software license by the [Free Software Foundation](http://www.fsf.org/), and has been vetted as an open source license by the [Open Source Initiative](http://www.opensource.org/).
+
+## The team
+
+TeXplate is brought to you by Ben Frank and Paulo Cereda. If you want to support TeX development by a donation, the best way to do this is donating to the [TeX Users Group](https://www.tug.org/donate.html).
+
diff --git a/Master/texmf-dist/doc/support/texplate/texplate-manual.pdf b/Master/texmf-dist/doc/support/texplate/texplate-manual.pdf
new file mode 100644
index 00000000000..98d06b0ca4e
--- /dev/null
+++ b/Master/texmf-dist/doc/support/texplate/texplate-manual.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/support/texplate/texplate-manual.tex b/Master/texmf-dist/doc/support/texplate/texplate-manual.tex
new file mode 100644
index 00000000000..6fe19fb5e40
--- /dev/null
+++ b/Master/texmf-dist/doc/support/texplate/texplate-manual.tex
@@ -0,0 +1,604 @@
+% arara: pdflatex
+% arara: pdflatex
+% arara: clean: { extensions: [ aux, listing, log, gz ] }
+\documentclass[11pt,article,twocolumn,a4paper]{memoir}
+
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+\usepackage[english]{babel}
+
+\usepackage{bookman}
+\usepackage[scaled=.9]{beramono}
+\usepackage{microtype}
+
+\newcommand{\texplate}{\TeX plate}
+\newcommand{\var}[1]{{\ttfamily\$#1}}
+\newcommand{\inline}[1]{{\ttfamily#1}}
+\newcommand{\shortopt}[1]{{\ttfamily-#1}}
+\newcommand{\longopt}[1]{{\ttfamily{-}{-}#1}}
+\newcommand{\macro}[1]{{\ttfamily\textbackslash#1}}
+\newcommand{\texplateversion}{1.0.1}
+
+\title{A gentle introduction to \texplate:\\ a document structure creation tool}
+\author{Island of \TeX}
+\date{Version \texplateversion\ -- \today}
+
+\usepackage{tcolorbox}
+\tcbuselibrary{listings}
+\tcbuselibrary{breakable}
+\tcbuselibrary{skins}
+
+\newtcblisting{code}{
+ colback=white,
+ colupper=black,
+ colframe=cyan!75!black,
+ listing only,
+ breakable,
+ enhanced,
+ before skip=10pt,
+ top=2pt,
+ left=4pt,
+ right=4pt,
+ bottom=2pt
+}
+\newtcolorbox{disclaimer}{
+ colback=white,
+ colupper=black,
+ colframe=cyan!75!black,
+ breakable,
+ enhanced,
+ before skip=10pt,
+ top=4pt,
+ left=4pt,
+ right=4pt,
+ bottom=4pt,
+ adjusted title=Disclaimer,
+ fonttitle=\bfseries,
+ fontupper=\em
+}
+
+\begin{document}
+
+\maketitle
+
+\begin{abstract}
+As the title implies, this document dares to be a gentle introduction to a rather unusual application, at least from our ordinary \TeX\ workflow: a tool for creating document structures based on templates. The application name is a word play on \emph{\TeX} and \emph{template}, so the purpose seems quite obvious: we want to provide an easy and straightforward framework for reducing the typical code boilerplate when writing \TeX\ documents. Also note that one can easily extrapolate the use beyond articles and theses: the application is powerful enough to generate \emph{any} text-based structure, given that a corresponding template exists.
+\end{abstract}
+
+\chapter{Introduction}
+\label{chap:introduction}
+
+A typical \TeX\ document usually contains a common preamble, the same code boilerplate we hold dear to keep our writing workflow efficient and, to an extent, satisfy our darkest typographic additions. A coherent preamble might significantly reduce the odds of having issues when compiling your document, but at the end of the day, it is always your fault when something terribly wrong happens in your code\footnote{This statement is suspiciously Carlislean. Also, since we are on the subject, make sure to never read documentation, as bad things happen.}. Anyway, consider the following \TeX\ document\footnote{Apologies in advance to every pizza connoisseur out there (specially Italians) for the provocative statement in the document. That said, one must accept the truth that Nutella pizza \emph{is} good.}:
+
+\begin{code}
+\documentclass{article}
+
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+
+\begin{document}
+This is the law of the jungle:
+Nutella pizza is good.
+\end{document}
+\end{code}
+
+Modulo actual content, this structure is probably recurring on the majority of documents using the classical engines. Ultimately, we aim at providing a collection of text-based structures through a comprehensive command line interface\footnote{Granted, command line usage is not exactly as friendly, intuitive and comprehensive as one could have ever hoped. We have plans for a graphical interface in the near future, so stay tuned.}, so as a means to reduce the code boilerplate for typical documents.
+
+\chapter{Concepts}
+\label{chap:concepts}
+
+Before introducing the command line application itself, we need to establish a common foundation and formally present a couple of concepts in which our tool is built. Consider this section as a primer to such elements.
+
+\section{Template}
+\label{sec:template}
+
+A template is basically a textual structure with certain entry points, in a sort of \emph{fill in the blanks} fashion. For \texplate, we rely on a template language provided by the Apache Foundation named VTL (or Velocity, for short), in its latest 2.0 specification, as of the writing of this manual.
+
+\begin{disclaimer}
+We do not intend to cover the language specification on its full glory in this manual. However, we might pinpoint and highlight some characteristics whenever relevant to the context.
+\end{disclaimer}
+
+For our purposes, the basic structure of any text-based document constitutes a template. For instance, the \TeX\ document originally presented in Section~\ref{chap:introduction}, modulo actual content, can certainly act as a verbatim template:
+
+\begin{code}
+\documentclass{article}
+
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+
+\begin{document}
+
+\end{document}
+\end{code}
+
+Note, however, that this template, as it is, does not hold any variables, conditional flows or sophisticated language constructs. The next concepts will build upon variables in the text, as a means to enhance the template expressiveness.
+
+\section{Map}
+\label{sec:map}
+
+A map is a collection of variables and values instantiated at run time and available within the template context. Since these values are specified in the command line, \texplate\ initially casts them as strings. It is worth noting, however, that these string values can be converted to arbitrary types later on through special functions named handlers in the template specification (see Section~\ref{sec:handlers} for further details). Regarding syntax, a variable \inline{bar} in the command line is referenced as a variable \var{bar} inside the template context. Note that all methods from the corresponding type class are available in the variable scope, since a variable acts like a proper Java object. However, note that it is highly advisable to verify whether a variable is defined before invoking any method. For instance, consider the following excerpt:
+
+\begin{code}
+#if($name)
+Hello, my name is $name.
+#else
+Hello, my name is John.
+#end
+\end{code}
+
+In this excerpt, observe that \var{name} is a variable. If such variable is properly specified in the command line, it will be set accordingly in the template context and the corresponding conditional branch is handled. Please refer to the VTL specification for further details.
+
+\begin{disclaimer}
+Ultimately, Java objects will rely on the \inline{toString()} method when the template is actually rendered, so there is no need to worry about converting arbitrary values back to strings.
+\end{disclaimer}
+
+The map is specified at run time, in the command line. It is important to observe that a variable might be marked as mandatory by the template (more on that later, when discussing the template specification in Chapter~\ref{chap:templatespecification}), so the absence of such variable in the map will trigger an exception and the tool will prematurely end.
+
+\chapter{Command line}
+\label{chap:commandline}
+
+Our tool is a typical command line application, so we need to invoke it by simply typing \inline{texplate} in the terminal:
+
+\begin{code}
+$ texplate
+\end{code}
+
+Provided that \texplate\ is properly available in the underlying operating system, we will get a lovely, colourful output in our terminal, along with a couple of scary messages telling that some required options are missing. Our tool provides four options, described as follows. Strictly speaking, there is only one mandatory option. The remainder might be optional, depending on certain scenarios.
+
+\section{Output}
+\label{sec:outputcli}
+
+Referred as either \shortopt{o} (short representation) or \longopt{output} (long representation), this option holds the output file in which the chosen template will be effectively written. The following examples are valid entries to this option:
+
+\begin{code}
+-o mydoc.tex
+-o=mydoc.tex
+--output mydoc.tex
+--output=mydoc.tex
+\end{code}
+
+The name is arbitrary, so you can use anything to your heart's desires. Keep in mind, however, that an existing file will be mercilessly overwritten. Also, make sure the path has the proper permissions for writing the output file.
+
+\section{Template}
+\label{sec:templatecli}
+
+Referred as either \shortopt{t} (short representation) or \longopt{template} (long representation), this option holds the reference to the template to be potentially merged with data and properly generated. The basic syntax is detailed as follows (note that \var{article} refers to the template identifier):
+
+\begin{code}
+-t article
+-t=article
+--template article
+--template=article
+\end{code}
+
+The provided string should match the template identifier, otherwise \texplate\ will raise an error complaining about the missing reference. The template identifier will be discussed later on, in Section~\ref{sec:namingscheme}.
+
+\section{Map}
+\label{sec:mapcli}
+
+Referred as either \shortopt{m} (short representation) or \longopt{map} (long representation), this option holds a map entry, defined as a \inline{key=value} ordered pair (mind the \inline{=} symbol used as entry separator). This option can be used multiple times. The following examples are valid entries to this option (note that \inline{foo} and \inline{bar} refer to an arbitrary map entry key and value, respectively):
+
+\begin{code}
+-m foo=bar
+-m=foo=bar
+--map foo=bar
+--map=foo=bar
+\end{code}
+
+The map entry denotes a variable in the template context, where the key is the variable name and the value is set to be the initial state of such variable. As the \longopt{map} option can be used multiple times, consider the following scenario, where the map entry key is repeated:
+
+\begin{code}
+--map foo=1 --map foo=2 --map foo=3
+\end{code}
+
+The final value associated to \inline{foo} is set to be the rightmost occurrence of the corresponding pair in the command line.
+
+\section{Configuration}
+\label{sec:configurationcli}
+
+\texplate\ also offers a configuration file in which the tool can read template data, for automation purposes. The configuration file is written in a text-based format named TOML\footnote{According to Wikipedia, TOML is a configuration file format intended to be easy to read and write due to obvious semantics and designed to map unambiguously to a dictionary. The syntax consists of entry pairs, sections and comments.} and can hold at most two sections: the template name as a string (with the same behaviour of \longopt{template} in the command line) and the contextual data map, with keys and associated values. A configuration file can have at least one of such sections, but never be empty. Consider the following configuration file:
+
+\begin{code}
+template = "article"
+
+[map]
+country = "Germany"
+year = 2020
+articles = [ "Die", "Der", "Das" ]
+\end{code}
+
+Observe that, contrary to the \longopt{map} option in the command line, the \inline{[map]} section in the configuration file accepts values other than strings (e.g., integers and lists of strings).
+
+\begin{disclaimer}
+Please keep in mind that map entries in the configuration file are not subjected to handlers (when available), as their command line counterparts are.
+\end{disclaimer}
+
+Command line options have priority over values originated from the configuration file. Given the previous configuration file,
+consider the following scenario:
+
+\begin{code}
+$ texplate -c config.toml -t book
+\end{code}
+
+Even though \inline{article} was the template set in the configuration, the \longopt{template} option has higher priority and thus the template is set to \inline{book}, as it is defined in the command line. The same logic is applied to map entries.
+
+\begin{disclaimer}
+Observe that, if a configuration file is being used and has no template key, the \longopt{template} option automatically becomes mandatory.
+\end{disclaimer}
+
+Note that \texplate\ has support for just one configuration file at run time. Support for multiple configurations might be added in the near future.
+
+\chapter{Template specification}
+\label{chap:templatespecification}
+
+\texplate\ uses predefined templates to generate text-based structures. Similar to the configuration structure presented in Section~\ref{sec:configurationcli}, the tool relies on text-based files written in TOML for holding the template specifications.
+
+\section{Naming scheme}
+\label{sec:namingscheme}
+
+For starters, a template has an identifier, a name that logically represents the text-based structure to be generated. Observe that the name corresponds to the reference used later on in the \longopt{template} option in the command line. A template file name has to match this identifier, so e.g., the \inline{article} reference is automatically linked to the \inline{article.toml} file which contains the template specification.
+
+\begin{disclaimer}
+Observe that \texplate's lookup system is case-sensitive, so make sure to always reference the correct name.
+\end{disclaimer}
+
+Although there are no hard limitations on a template name, it is advisable to keep it short and concise, with no spaces whatsoever\footnote{Another Carlislean statement would remind us that people that put spaces in their file names deserve no sympathy. At all.}. As a consequence, potential issues with extended characters in the Unicode range and command line escaping are avoided, and thus our beloved tool might just work as expected.
+
+\section{Directory lookup}
+\label{sec:directorylookup}
+
+\texplate\ employs a lookup system that basically searches two locations for template files (specifications written in the TOML format), in order of priority:
+
+\begin{enumerate}
+\item\inline{\textasciitilde/.texplate/templates} which refers to a path structure from the user home directory.
+
+\item\inline{<APP>/templates} which refers to a path structure from the application directory (with \inline{<APP>} denoting the location where \texplate\ is installed).
+\end{enumerate}
+
+For instance, as a means to illustrate the concept of directory lookup, consider the following command line command:
+
+\begin{code}
+$ texplate -t article -o mydoc.tex
+\end{code}
+
+\texplate\ will look for a template file named \inline{article.toml} in the path structure from the user home directory, as seen in \#1. If the file is found, the search ends and the tool proceeds to the template generation. Otherwise, \texplate\ will attempt to look in its own template folder for a match. If found, the tool will use this file reference. If the template file is not found in any of the two locations, the tool reports the issue and prematurely ends.
+
+\section{Handlers}
+\label{sec:handlers}
+
+A map entry, when obtained from the command line through the \longopt{map} option, holds a string value. \texplate\ provides a straightforward way to convert string values to arbitrary types through special functions named handlers in the template specification. The following handlers are available for type conversion:
+
+\begin{itemize}
+\item\inline{to-csv-list}: this handler, as the name implies, converts a string to a list of comma-separated values. The implementation attempts to respect quoted elements, when available.
+\item\inline{to-boolean}: this handler converts a string to a boolean value, based on the following patterns: \inline{true} and \inline{false}, \inline{1} and \inline{0}, and \inline{yes} or \inline{no}.
+\end{itemize}
+
+When type conversion is needed in the template logic, handlers are assigned to map keys in the corresponding specification, detailed later on, in Section~\ref{sec:templatestructure}.
+
+\begin{disclaimer}
+Handlers are internal functions provided by \texplate\ that map String values to arbitrary types.
+\end{disclaimer}
+
+When referencing handlers, make sure to write the correct name in the template specification, so the lookup and subsequent call work as expected.
+
+\section{Template structure}
+\label{sec:templatestructure}
+
+The template structure holds at most two sections: the template itself and an optional \inline{[handlers]} section holding the handlers to be applied to certain map entries. The following keys are required for the first section (i.e., the template definition):
+
+\begin{itemize}
+\item\inline{name}: this key holds a string value that denotes the template name. Observe that \texplate\ requires this key to hold the exact value of the template identifier, as described in Section~\ref{sec:namingscheme}.
+
+\begin{code}
+name = "mytemplate"
+\end{code}
+
+\item\inline{description}: this key holds a string value that provides a short yet meaningful description for the template being written. It is usually suitable to use the \inline{"""} (triple double quotes) notation for this key, as it allows long strings to span multiple lines (and ignore line breaks).
+
+\begin{code}
+description = """
+A simple template used to
+illustrate the template
+structure.
+"""
+\end{code}
+
+\item\inline{authors}: this key, as the name implies, holds a list of strings denoting the template authors, for obvious blaming purposes, in case anything goes terribly wrong\footnote{Of course, it is important to observe that an error, exception or issue is definitely \emph{not our fault}.}.
+
+\begin{code}
+authors = [ "Alice", "Bob" ]
+\end{code}
+
+\item\inline{requirements}: this key holds a list of strings denoting potential requirements for the template. For instance, the template might require some variables to be specified at run time, either through the command line or configuration file:
+
+\begin{code}
+requirements = [ "names" ]
+\end{code}
+
+If the requirements are not complied, \texplate\ will report the issue and prematurely end. When the template imposes no requirements at all, make sure to provide an empty list:
+
+\begin{code}
+requirements = [ ]
+\end{code}
+
+\item\inline{document}: this key, as the name suggests, holds the actual text-based document, written using the VTL specification (or any subset of it). It is usually suitable to use the \inline{{'}{'}{'}} (triple single quotes) notation for this key, as it allows raw strings (i.e., literal reproduction with no need of escaping characters) and multiple lines while respecting breaks.
+
+\begin{code}
+document = '''
+These are the names:
+
+\begin{itemize}
+#foreach ($name in $names)
+ \item $name
+#end
+\end{itemize}
+'''
+\end{code}
+
+\end{itemize}
+
+The \inline{[handlers]} section, as the name indicates, holds potential handler references to be applied to certain map entries. These references are set as strings. For instance, \var{names} is actually a list of strings, so a type conversion has to be employed:
+
+\begin{code}
+[handlers]
+names = "to-csv-list"
+\end{code}
+
+Observe that, if there is no need for handlers in the template structure, this section might safely be omitted.
+
+\chapter{A complete example}
+\label{chap:completeexample}
+
+Now that all concepts are formally introduced in the previous chapters, it is time to glue everything together. The following steps cover the basics from creating a template to merging data into it:
+
+\begin{enumerate}
+\item First and foremost, let us create a template named \inline{mytemplate}, inspired on the previous content presented in this user manual. The naming scheme, as well as the directory structure, must be respected, so open your favourite editor\footnote{Your favourite editor should be \inline{vim}, of course. Anything else is simply wrong and unacceptable.} and create the following file:
+
+\begin{code}
+$ mkdir -p ~/.texplate/templates/
+$ cd ~/.texplate/templates/
+$ vim myarticle.toml
+\end{code}
+
+\item Now, add the following content to the newly created \inline{mytemplate.toml} file:
+
+\begin{code}
+name = "mytemplate"
+description = """
+A simple template used to
+illustrate the template
+structure.
+"""
+authors = [ "Alice", "Bob" ]
+requirements = [ "names" ]
+document = '''
+These are the names:
+
+\begin{itemize}
+#foreach ($name in $names)
+ \item $name
+#end
+\end{itemize}
+'''
+
+[handlers]
+names = "to-csv-list"
+\end{code}
+
+\item Done, the template is ready to be used! Now, simply call \texplate\ in the command line and provide the required map entry, as seen as follows:
+
+\begin{code}
+$ texplate -t mytemplate -m names=John,Jane -o list.tex
+\end{code}
+
+The output (i.e., the template merged with the provided data) will be written to a text-based file named \inline{list.tex}.
+
+\item When running \texplate, this is the expected output to be displayed in the command line (note that the layout is slightly modified due to space constraints in this user manual):
+
+\begin{code}
+TeXplate 1.0.1, a document structure creation tool
+Copyright (c) 2020, Island of TeX
+All rights reserved.
+
+Configuration file
+mode disabled ......... [ DONE ]
+Entering full
+command line mode ..... [ DONE ]
+
+Please, wait...
+
+Obtaining reference ... [ DONE ]
+Composing template .... [ DONE ]
+Validating data ....... [ DONE ]
+Merging template
+and data .............. [ DONE ]
+
+Done! Enjoy your template!
+Written: 78 B
+\end{code}
+
+\item Great, everything worked as expected! Now, let us check the contents of the newly generated \inline{list.tex} file:
+
+\begin{code}
+$ cat list.tex
+These are the names:
+
+\begin{itemize}
+ \item John
+ \item Jane
+\end{itemize}
+\end{code}
+
+As seen in the previous output, the template and provided data were successfully merged.
+
+\item Let us reproduce the same output with a configuration file. Observe, however, that handlers are not applied to map entries in the configuration file, so we have to explicitly set \inline{names} as a list of strings. Let us create a configuration file named \inline{config.toml} in the current directory:
+
+\begin{code}
+$ vim config.toml
+\end{code}
+
+Now, add the following content to the newly created \inline{config.toml} file:
+
+\begin{code}
+template = "mytemplate"
+
+[map]
+names = [ "John", "Jane" ]
+\end{code}
+
+\item The new call to \texplate, given the aforementioned configuration file, is slightly different than the previous one (step 3), so write the following entry in the command line:
+
+\begin{code}
+$ texplate -c config.toml -o list.tex
+\end{code}
+
+\item The output is pretty much the same obtained in the previous call (step 4), except for the following lines acknowledging the configuration file mode:
+
+\begin{code}
+Checking
+configuration .......... [ DONE ]
+Adjusting variables
+from file .............. [ DONE ]
+\end{code}
+
+The final lines from \texplate\ indicate everything worked as expected:
+
+\begin{code}
+Done! Enjoy your template!
+Written: 78 B
+\end{code}
+
+\item The generated \inline{list.tex} file has exactly the same contents as illustrated in step 5. It is important to remember that an existing output file will be mercilessly overwritten.
+\end{enumerate}
+
+The previous steps described how \texplate\ works, from creating a template to merging data into it, as a means to generating a text-based document. Chapter~\ref{chap:includedtemplates} presents text-based templates shipped with our tool, as well as the available variables in the document context.
+
+\chapter{Included templates}
+\label{chap:includedtemplates}
+
+\texplate\ ships with the following text-based templates, automatically available from the application directory:
+
+\section*{\inline{article}}
+
+This reference holds a simple template for the default \inline{article} class, with support for new engines (with \inline{fontspec} fallback), \inline{babel} languages, geometry options, generic packages, and Ti\textit{k}Z and corresponding libraries. There are no requirements for this template. Available variables are described as follows:
+
+\begin{itemize}
+\item\inline{xetex}: boolean value, changes the default behaviour to accommodate the Xe\TeX\ engine. Typical \inline{fontenc} and \inline{inputenc} packages are replaced by \inline{fontspec} when this variable holds true (semantically equivalent).
+
+\begin{code}
+-m xetex=true
+\end{code}
+
+\item\inline{luatex}: boolean value, changes the default behaviour to accommodate the Lua\TeX\ engine. Typical \inline{fontenc} and \inline{inputenc} packages are replaced by \inline{fontspec} when this variable holds true (semantically equivalent).
+
+\begin{code}
+-m luatex=true
+\end{code}
+
+\item\inline{options}: string value, holds the document class options, when applied.
+
+\begin{code}
+-m options=12pt,a4paper
+\end{code}
+
+\item\inline{babel}: string value, holds a sequence of languages supported by the \inline{babel} package. Keep in mind that the last entry in the sequence is set to be the default language.
+
+\begin{code}
+-m babel=english,italian
+\end{code}
+
+\item\inline{geometry}: string value, holds the options for the \inline{geometry} package. It is important to note that order matters.
+
+\begin{code}
+-m geometry=margins=2cm
+\end{code}
+
+\item\inline{packages}: list of strings, holds a list of packages to be included in the document preamble, in the specified order.
+
+\begin{code}
+-m packages=longtable,array
+\end{code}
+
+\item\inline{tikz}: boolean value, checks whether the document should include support for Ti\textit{k}Z in the preamble.
+
+\begin{code}
+-m tikz=true
+\end{code}
+
+\item\inline{libraries}: list of strings, holds a list of Ti\textit{k}Z libraries to be included in the document preamble, in the specified order. It is important to observe that this variable has no effect whatsoever if the \inline{tikz} variable is either not set or does not hold true.
+
+\begin{code}
+-m libraries=automata,positioning
+\end{code}
+\end{itemize}
+
+\section*{\inline{standalone}}
+
+This reference holds a simple template for the \inline{standalone} class, with support for new engines (with \inline{fontspec} fallback), \inline{babel} languages, geometry options, generic packages, and Ti\textit{k}Z and corresponding libraries. There are no requirements for this template. Available variables are described as follows:
+
+\begin{itemize}
+\item\inline{xetex}: boolean value, changes the default behaviour to accommodate the Xe\TeX\ engine. Typical \inline{fontenc} and \inline{inputenc} packages are replaced by \inline{fontspec} when this variable holds true (semantically equivalent).
+
+\begin{code}
+-m xetex=true
+\end{code}
+
+\item\inline{luatex}: boolean value, changes the default behaviour to accommodate the Lua\TeX\ engine. Typical \inline{fontenc} and \inline{inputenc} packages are replaced by \inline{fontspec} when this variable holds true (semantically equivalent).
+
+\begin{code}
+-m luatex=true
+\end{code}
+
+\item\inline{options}: string value, holds the document class options, when applied.
+
+\begin{code}
+-m options=12pt,a4paper
+\end{code}
+
+\item\inline{babel}: string value, holds a sequence of languages supported by the \inline{babel} package. Keep in mind that the last entry in the sequence is set to be the default language.
+
+\begin{code}
+-m babel=english,italian
+\end{code}
+
+\item\inline{geometry}: string value, holds the options for the \inline{geometry} package. It is important to note that order matters.
+
+\begin{code}
+-m geometry=margins=2cm
+\end{code}
+
+\item\inline{packages}: list of strings, holds a list of packages to be included in the document preamble, in the specified order.
+
+\begin{code}
+-m packages=longtable,array
+\end{code}
+
+\item\inline{tikz}: boolean value, checks whether the document should include support for Ti\textit{k}Z in the preamble.
+
+\begin{code}
+-m tikz=true
+\end{code}
+
+\item\inline{libraries}: list of strings, holds a list of Ti\textit{k}Z libraries to be included in the document preamble, in the specified order. It is important to observe that this variable has no effect whatsoever if the \inline{tikz} variable is either not set or does not hold true.
+
+\begin{code}
+-m libraries=automata,positioning
+\end{code}
+\end{itemize}
+
+\chapter{Final remarks}
+\label{chap:finalremarks}
+
+This document aimed at being a gentle introduction to \texplate, a tool for creating document structures based on templates. We invite you to contribute to this project by submitting feature requests, issues and new templates:
+
+\begin{code}
+gitlab.com/islandoftex/texplate
+\end{code}
+
+Happy \TeX ing with \texplate!
+
+\section*{License}
+
+\texplate\ is licensed under the New BSD License. Please note that the New BSD License has been verified as a GPL-compatible free software license by the Free Software Foundation, and has been vetted as an open source license by the Open Source Initiative.
+
+\end{document}
diff --git a/Master/texmf-dist/scripts/texplate/templates/texplate-article.toml b/Master/texmf-dist/scripts/texplate/templates/texplate-article.toml
new file mode 100644
index 00000000000..53f7796762c
--- /dev/null
+++ b/Master/texmf-dist/scripts/texplate/templates/texplate-article.toml
@@ -0,0 +1,54 @@
+name = "article"
+description = """
+A simple template for the default article class, with support for new
+engines (with fontspec fallback), babel languages, geometry options,
+generic packages, and TikZ and corresponding libraries.
+"""
+authors = [ "Island of TeX" ]
+requirements = []
+document = '''
+\documentclass#if($options)[$options]#{end}{article}
+
+#if ($xetex || $luatex)
+\usepackage{fontspec}
+#else
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+#end
+#if ($geometry)
+
+\usepackage[$geometry]{geometry}
+#end
+#if ($babel)
+#if (!$geometry)
+
+#end
+\usepackage[$babel]{babel}
+#end
+#if ($packages)
+
+#foreach ($package in $packages)
+\usepackage{$package}
+#end
+#end
+#if ($tikz)
+
+\usepackage{tikz}
+#if ($libraries)
+#foreach ($library in $libraries)
+\usetikzlibrary{$library}
+#end
+#end
+#end
+
+\begin{document}
+
+\end{document}
+'''
+
+[handlers]
+xetex = "to-boolean"
+luatex = "to-boolean"
+tikz = "to-boolean"
+libraries = "to-csv-list"
+packages = "to-csv-list"
diff --git a/Master/texmf-dist/scripts/texplate/templates/texplate-standalone.toml b/Master/texmf-dist/scripts/texplate/templates/texplate-standalone.toml
new file mode 100644
index 00000000000..dd8daea65f5
--- /dev/null
+++ b/Master/texmf-dist/scripts/texplate/templates/texplate-standalone.toml
@@ -0,0 +1,45 @@
+name = "standalone"
+description = """
+A simple template for the standalone class, with support for
+class options, new engines (with fontspec fallback), list of
+packages, and TikZ and corresponding libraries.
+"""
+authors = [ "Island of TeX" ]
+requirements = []
+document = '''
+\documentclass#if($options)[$options]#{end}{standalone}
+
+#if ($xetex || $luatex)
+\usepackage{fontspec}
+#else
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+#end
+#if ($packages)
+
+#foreach ($package in $packages)
+\usepackage{$package}
+#end
+#end
+#if ($tikz)
+
+\usepackage{tikz}
+#if ($libraries)
+#foreach ($library in $libraries)
+\usetikzlibrary{$library}
+#end
+#end
+#end
+
+\begin{document}
+
+\end{document}
+'''
+
+[handlers]
+xetex = "to-boolean"
+luatex = "to-boolean"
+tikz = "to-boolean"
+libraries = "to-csv-list"
+packages = "to-csv-list"
+
diff --git a/Master/texmf-dist/scripts/texplate/texplate.jar b/Master/texmf-dist/scripts/texplate/texplate.jar
new file mode 100644
index 00000000000..2105a4c33c0
--- /dev/null
+++ b/Master/texmf-dist/scripts/texplate/texplate.jar
Binary files differ
diff --git a/Master/texmf-dist/scripts/texplate/texplate.sh b/Master/texmf-dist/scripts/texplate/texplate.sh
new file mode 100644
index 00000000000..da649780378
--- /dev/null
+++ b/Master/texmf-dist/scripts/texplate/texplate.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Public domain. Originally written by Norbert Preining and Karl Berry, 2018.
+# Note from Paulo: this script provides better Cygwin support than our original
+# approach, so the team decided to use it as a proper wrapper for texplate as well.
+
+scriptname=`basename "$0"`
+jar="$scriptname.jar"
+jarpath=`kpsewhich --progname="$scriptname" --format=texmfscripts "$jar"`
+
+kernel=`uname -s 2>/dev/null`
+if echo "$kernel" | grep CYGWIN >/dev/null; then
+ CYGWIN_ROOT=`cygpath -w /`
+ export CYGWIN_ROOT
+ jarpath=`cygpath -w "$jarpath"`
+fi
+
+exec java -jar "$jarpath" "$@" \ No newline at end of file
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/Main.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/Main.java
new file mode 100644
index 00000000000..5c27aab23c0
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/Main.java
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate;
+
+import org.islandoftex.texplate.model.TemplateProcessing;
+import org.islandoftex.texplate.util.MessageUtils;
+import picocli.CommandLine;
+
+/**
+ * The main class. The application logic is enclosed in the template processing
+ * class.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class Main {
+
+ /**
+ * Main method. Note that it simply passes the control to the template
+ * processing class.
+ *
+ * @param args The command line arguments.
+ */
+ public static void main(String[] args) {
+
+ // draw the application logo in the
+ // terminal (please have fixed fonts
+ // in your terminal for a nice display)
+ MessageUtils.drawLogo();
+
+ // calls the command line processing method
+ // and performs the actual application logic
+ int exitCode = new CommandLine(new TemplateProcessing()).execute(args);
+ System.exit(exitCode);
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/InvalidKeySetException.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/InvalidKeySetException.java
new file mode 100644
index 00000000000..3d113a25998
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/InvalidKeySetException.java
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.exceptions;
+
+/**
+ * Handles exceptions when the context map contains invalid keys.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class InvalidKeySetException extends Exception {
+
+ /**
+ * Constructor.
+ */
+ public InvalidKeySetException() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message Message to be attached to the exception.
+ */
+ public InvalidKeySetException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message Message to be attached to the exception.
+ * @param cause The throwable cause to be forwarded.
+ */
+ public InvalidKeySetException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/InvalidTemplateException.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/InvalidTemplateException.java
new file mode 100644
index 00000000000..73c82769980
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/InvalidTemplateException.java
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.exceptions;
+
+/**
+ * Handles exceptions when the template is somehow invalid.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class InvalidTemplateException extends Exception {
+
+ public InvalidTemplateException() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message Message to be attached to the exception.
+ */
+ public InvalidTemplateException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message Message to be attached to the exception.
+ * @param cause The throwable cause to be forwarded.
+ */
+ public InvalidTemplateException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/TemplateMergingException.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/TemplateMergingException.java
new file mode 100644
index 00000000000..86dd99af00f
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/TemplateMergingException.java
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.exceptions;
+
+/**
+ * Handles exceptions when the template merging failed.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class TemplateMergingException extends Exception {
+
+ /**
+ * Constructor.
+ */
+ public TemplateMergingException() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message Message to be attached to the exception.
+ */
+ public TemplateMergingException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message Message to be attached to the exception.
+ * @param cause The throwable cause to be forwarded.
+ */
+ public TemplateMergingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Configuration.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Configuration.java
new file mode 100644
index 00000000000..a0f8e837029
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Configuration.java
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model;
+
+import com.moandjiezana.toml.Toml;
+import io.vavr.control.Try;
+import org.islandoftex.texplate.exceptions.InvalidTemplateException;
+
+import java.nio.file.Path;
+import java.util.Map;
+
+/**
+ * The configuration model.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class Configuration {
+
+ // template of the template
+ private String template;
+
+ // map of variables for the configuration
+ private Map<String, Object> map;
+
+ /**
+ * Constructor.
+ */
+ public Configuration() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param template The template.
+ * @param map The map.
+ */
+ public Configuration(String template, Map<String, Object> map) {
+ this.template = template;
+ this.map = map;
+ }
+
+ /**
+ * Gets the template.
+ *
+ * @return The template.
+ */
+ public String getTemplate() {
+ return template;
+ }
+
+ /**
+ * Sets the template.
+ *
+ * @param template The template.
+ */
+ public void setTemplate(String template) {
+ this.template = template;
+ }
+
+ /**
+ * Gets the map.
+ *
+ * @return The map.
+ */
+ public Map<String, Object> getMap() {
+ return map;
+ }
+
+ /**
+ * Sets the map.
+ *
+ * @param map The map.
+ */
+ public void setMap(Map<String, Object> map) {
+ this.map = map;
+ }
+
+ /**
+ * Checks whether the configuration is valid.
+ *
+ * @return A boolean value indicating whether the configuration is valid.
+ */
+ private boolean isValid() {
+ return !(template == null || map == null);
+ }
+
+ /**
+ * Reads the configuration from path.
+ *
+ * @param path The path.
+ * @return Configuration.
+ * @throws InvalidTemplateException The configuration is invalid.
+ */
+ private static Configuration readFromPath(Path path)
+ throws InvalidTemplateException {
+
+ // the actual configuration
+ Configuration configuration;
+
+ // the default message
+ String message = "The provided configuration file looks invalid. "
+ + "Please make sure the configuration has a valid syntax and "
+ + "try again. ";
+
+ try {
+
+ // gets the configuration
+ configuration = new Toml().read(path.toFile()).
+ to(Configuration.class);
+
+ } catch (Exception exception) {
+
+ // the configuration
+ // seems invalid
+ throw new InvalidTemplateException(message + "In this particular "
+ + "scenario, there is a possibility that the configuration "
+ + "file does not follow the TOML specification. Please "
+ + "refer to the user manual for further details and a "
+ + "possible fix. Also, the raised exception message can "
+ + "give us some hints on what happened.", exception);
+ }
+
+ // checks whether the
+ // configuration is valid
+ if (configuration.isValid()) {
+
+ // returns the configuration
+ return configuration;
+ } else {
+
+ // the configuration
+ // is invalid
+ throw new InvalidTemplateException(message + "Specifically, some "
+ + "mandatory fields are either absent or empty in the "
+ + "configuration file. It is quite important to strictly "
+ + "follow the configuration specification, as detailed in "
+ + "the user manual, or the tool will not work at all.");
+ }
+ }
+
+ /**
+ * Gets the configuration from a path.
+ *
+ * @param path The path.
+ * @return The configuration.
+ */
+ public static Try<Configuration> of(Path path) {
+ return Try.of(() -> readFromPath(path));
+ }
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Template.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Template.java
new file mode 100644
index 00000000000..ca92e046584
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Template.java
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model;
+
+import com.moandjiezana.toml.Toml;
+import io.vavr.control.Try;
+import org.islandoftex.texplate.exceptions.InvalidTemplateException;
+
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The template model.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class Template {
+
+ // name of the template
+ private String name;
+
+ // description of the template
+ private String description;
+
+ // list of authors who wrote the template
+ private List<String> authors;
+
+ // list of requirements for the template
+ private List<String> requirements;
+
+ // the document to be configured
+ private String document;
+
+ // the map handlers
+ private Map<String, String> handlers;
+
+ /**
+ * Constructor.
+ */
+ public Template() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name Name of the template.
+ * @param description Description of the template.
+ * @param authors List of authors of the template.
+ * @param requirements List of requirements for the template.
+ * @param document The document to be configured.
+ * @param handlers The optional map handlers.
+ */
+ public Template(String name, String description, List<String> authors,
+ List<String> requirements, String document,
+ Map<String, String> handlers) {
+ this.name = name;
+ this.description = description;
+ this.authors = authors;
+ this.requirements = requirements;
+ this.document = document;
+ this.handlers = handlers;
+ }
+
+ /**
+ * Gets the template name.
+ *
+ * @return The template name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the template name.
+ *
+ * @param name The template name.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Gets the template description.
+ *
+ * @return The template description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Sets the template description.
+ *
+ * @param description The template description.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Gets the template authors.
+ *
+ * @return The template authors.
+ */
+ public List<String> getAuthors() {
+ return authors;
+ }
+
+ /**
+ * Sets the template authors.
+ *
+ * @param authors The template authors.
+ */
+ public void setAuthors(List<String> authors) {
+ this.authors = authors;
+ }
+
+ /**
+ * Gets the template requirements.
+ *
+ * @return The template requirements.
+ */
+ public List<String> getRequirements() {
+ return requirements;
+ }
+
+ /**
+ * Sets the template requirements.
+ *
+ * @param requirements The template requirements.
+ */
+ public void setRequirements(List<String> requirements) {
+ this.requirements = requirements;
+ }
+
+ /**
+ * Gets the template document.
+ *
+ * @return The template document.
+ */
+ public String getDocument() {
+ return document;
+ }
+
+ /**
+ * Sets the template document.
+ *
+ * @param document The template document.
+ */
+ public void setDocument(String document) {
+ this.document = document;
+ }
+
+ /**
+ * Gets the map handlers.
+ *
+ * @return The map handlers.
+ */
+ public Map<String, String> getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Sets the map handlers.
+ *
+ * @param handlers The map handlers.
+ */
+ public void setHandlers(Map<String, String> handlers) {
+ this.handlers = handlers;
+ }
+
+ /**
+ * Checks whether the template is valid.
+ *
+ * @return A boolean value indicating whether the template is valid.
+ */
+ private boolean isValid() {
+ return !((name == null) || (description == null)
+ || (authors == null) || (requirements == null)
+ || (document == null) || name.trim().isEmpty()
+ || description.trim().isEmpty() || authors.isEmpty()
+ || document.trim().isEmpty());
+ }
+
+ /**
+ * Reads the template from the provided path.
+ *
+ * @param path The path to the template file.
+ * @return The template object from the provided path.
+ * @throws InvalidTemplateException The template is invalid.
+ */
+ private static Template readFromPath(Path path)
+ throws InvalidTemplateException {
+
+ // the actual template
+ Template template;
+
+ // the exception message, in case the
+ // conversion fails or if there are
+ // missing elements from the template
+ String message = "The provided template file looks invalid. Please "
+ + "make sure the template has a valid syntax and try again. ";
+
+ try {
+
+ // reads the file and converts
+ // the TOML format into the object
+ template = new Toml().read(path.toFile()).to(Template.class);
+
+ } catch (Exception exception) {
+
+ // throws the new exception and
+ // attaches the original cause
+ throw new InvalidTemplateException(message + "In this particular "
+ + "scenario, there is a possibility that the template "
+ + "file does not follow the TOML specification. Please "
+ + "refer to the user manual for further details and a "
+ + "possible fix. Also, the raised exception message can "
+ + "give us some hints on what happened.", exception);
+ }
+
+ // the conversion hasn't failed, but we need
+ // to check whether the template is valid
+ if (template.isValid()) {
+
+ // everything went fine, so
+ // simply return the template
+ return template;
+ } else {
+
+ // the template is invalid, so we
+ // need to throw an exception
+ throw new InvalidTemplateException(message + "Specifically, some "
+ + "mandatory fields are either absent or empty in the "
+ + "template file. It is quite important to strictly "
+ + "follow the template specification, as detailed in the "
+ + "user manual, or the tool will not work at all.");
+ }
+ }
+
+ /**
+ * Returns the template from the provided path.
+ *
+ * @param path The path in which the template is retrieved.
+ * @return The corresponding template, enclosed in a Try object.
+ */
+ public static Try<Template> of(Path path) {
+ return Try.of(() -> readFromPath(path));
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/TemplateProcessing.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/TemplateProcessing.java
new file mode 100644
index 00000000000..eccaf6c7320
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/TemplateProcessing.java
@@ -0,0 +1,391 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model;
+
+import io.vavr.control.Either;
+import org.islandoftex.texplate.util.MergingUtils;
+import org.islandoftex.texplate.util.MessageUtils;
+import org.islandoftex.texplate.util.PathUtils;
+import org.islandoftex.texplate.util.ValidatorUtils;
+import picocli.CommandLine;
+import picocli.CommandLine.Option;
+
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+/**
+ * The template processing class.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+@CommandLine.Command(
+ usageHelpWidth = 70,
+ name = "texplate"
+)
+public class TemplateProcessing implements Callable<Integer> {
+
+ // the file output, which will hold the
+ // result of the merging of both template
+ // and context data map from command line
+ @Option(
+ names = {"-o", "--output"},
+ description = "The output file in which the chosen "
+ + "template will be effectively written. Make sure "
+ + "the directory has the correct permissions for "
+ + "writing the output file.",
+ required = true,
+ type = Path.class
+ )
+ private Path output;
+
+ // the template name
+ @Option(
+ names = {"-t", "--template"},
+ description = "The template and. The tool will "
+ + "search both user and system locations and set the "
+ + "template model accordingly, based on your specs."
+ )
+ private String template;
+
+ // the context data map that holds
+ // a set of key/value pairs to be
+ // merged with the template
+ @Option(
+ names = {"-m", "--map"},
+ description = "The contextual map that provides the "
+ + "data to be merged in the template. This parameter "
+ + "can be used multiple times. You can specify a map "
+ + "entry with the key=value syntax (mind the entry "
+ + "separator).",
+ arity = "1..*"
+ )
+ private Map<String, String> map;
+
+ @Option(
+ names = {"-c", "--config"},
+ description = "The configuration file in which the tool "
+ + "can read template data, for automation purposes. Make "
+ + "sure to follow the correct specification when writing "
+ + "a configuration file.",
+ type = Path.class
+ )
+ private Path configuration;
+
+ /**
+ * The application logic, enclosed as a call method.
+ *
+ * @return An integer value denoting the exit status.
+ * @throws Exception An exception was raised in the application logic.
+ */
+ @Override
+ public Integer call() throws Exception {
+
+ // the exit status, originally
+ // set as a valid value
+ int exit = 0;
+
+ // configuration halt flag, indicating
+ // whether the tool has to end earlier
+ boolean halt = false;
+
+ Map<String, Object> cmap = new HashMap<>();
+
+ // ensure the context data map
+ // is at least instantiated
+ ensureMap();
+
+ // there is a configuration file
+ // found in the command line
+ if (has(configuration)) {
+
+ // print the configuration
+ // check line for status
+ MessageUtils.line("Checking configuration");
+
+ // try to read the configuration
+ // file into a proper object
+ Either<Throwable, Configuration> configChecking = Configuration.
+ of(configuration).toEither();
+
+ // the configuration file
+ // seems to be valid, proceed
+ if (configChecking.isRight()) {
+
+ // print status line
+ MessageUtils.status(true);
+
+ // get the configuration file
+ Configuration config = configChecking.get();
+
+ // check if the configuration
+ // has a proper template
+ if (has(config.getTemplate())) {
+
+ // if so, build the template if, and
+ // only if, there's no one already
+ // set through command line
+ template = ensure(template, config.getTemplate());
+ }
+
+ // check if the configuration
+ // has a proper string/string map
+ if (has(config.getMap())) {
+
+ // set the main configuration
+ // map to be dealt later on
+ cmap = config.getMap();
+ }
+
+ // print header about tidying
+ // up configuration variables
+ MessageUtils.line("Adjusting variables from file");
+ MessageUtils.status(true);
+ System.out.println();
+
+ } else {
+
+ // an error occurred, print it
+ // set exit code and halt
+ MessageUtils.status(false);
+ MessageUtils.error(configChecking.getLeft());
+ exit = -1;
+ halt = true;
+ }
+ } else {
+
+ // print header regarding
+ // no config file found
+ MessageUtils.line("Configuration file mode disabled");
+ MessageUtils.status(true);
+
+ // print a header regarding
+ // full command line mode
+ MessageUtils.line("Entering full command line mode");
+
+ // there's no configuration file, so we
+ // need to check whether there is not a
+ // pattern set in the command line
+ if (!has(template)) {
+
+ // print status
+ MessageUtils.status(false);
+
+ // print message
+ MessageUtils.error(new Exception("The template was not set "
+ + "in the command line through the -t/--template "
+ + "option. If not explicitly specified in a "
+ + "configuration file, this option becomes mandatory, "
+ + "so make sure to define it either in the command "
+ + "line or in a proper configuration file."));
+
+ exit = -1;
+ halt = true;
+
+ } else {
+
+ // print status
+ MessageUtils.status(true);
+ System.out.println();
+ }
+
+ }
+
+ // check whether we should
+ // halt prematurely
+ if (!halt) {
+
+ // initial message, preparing our
+ // hearts to the actual merging :)
+ System.out.println("Please, wait...");
+ System.out.println();
+
+ // now we need to obtain the actual
+ // template from a file stored either
+ // in the user home or in the system
+ MessageUtils.line("Obtaining reference");
+
+ // let us try to get the corresponding
+ // file from the template pattern
+ Either<Throwable, Path> fileChecking = PathUtils.
+ getTemplatePath(template).toEither();
+
+ // the actual template file was
+ // found, so we can proceed to
+ // the next phase
+ if (fileChecking.isRight()) {
+
+ // updates the current
+ // status accordingly
+ MessageUtils.status(true);
+
+ // now it's time to compose the template
+ // object from its corresponding file
+ MessageUtils.line("Composing template");
+
+ // attempts to retrieve the template
+ // attributes from the referenced file
+ // to the actual template object
+ Either<Throwable, Template> templateComposition
+ = Template.of(fileChecking.get()).toEither();
+
+ // the template composition was successful,
+ // so we can move on to the next phase
+ if (templateComposition.isRight()) {
+
+ // updates the current
+ // status accordingly
+ MessageUtils.status(true);
+
+ // once the template object is populated,
+ // we need to verify if both template and
+ // data map are not somehow conflicting
+ MessageUtils.line("Validating data");
+ Either<Throwable, Map<String, String>> dataValidation
+ = ValidatorUtils.validate(templateComposition.get(),
+ map).toEither();
+
+ // the data validation was consistent,
+ // so now the merging can be applied
+ if (dataValidation.isRight()) {
+
+ // updates the current
+ // status accordingly
+ MessageUtils.status(true);
+
+ // now it's the final phase, in which
+ // both template and data are merged
+ MessageUtils.line("Merging template and data");
+
+ // merge both template and context data
+ // map
+ Either<Throwable, Long> merging = MergingUtils.
+ merge(templateComposition.get(),
+ dataValidation.get(),
+ output, cmap).toEither();
+
+ // the merging was successful,
+ // so now there's nothing else
+ // to do, yay!
+ if (merging.isRight()) {
+
+ // updates the current
+ // status accordingly
+ MessageUtils.status(true);
+
+ // print the final messge and
+ // tell the user everything
+ // went smooth!
+ System.out.println();
+ System.out.println("Done! Enjoy your template!");
+ System.out.println("Written: "
+ + getSize(merging.get()));
+ } else {
+
+ // updates the current
+ // status accordingly
+ MessageUtils.status(false);
+
+ // the merging failed, so the
+ // exception is displayed and
+ // the exit status is updated
+ MessageUtils.error(merging.getLeft());
+ exit = -1;
+ }
+ } else {
+
+ // updates the current
+ // status accordingly
+ MessageUtils.status(false);
+
+ // the data validation failed, so
+ // the exception is displayed and
+ // the exit status is updated
+ MessageUtils.error(dataValidation.getLeft());
+ exit = -1;
+ }
+ } else {
+
+ // updates the current
+ // status accordingly
+ MessageUtils.status(false);
+
+ // the template composition failed,
+ // so the exception is displayed and
+ // the exit status is updated
+ MessageUtils.error(templateComposition.getLeft());
+ exit = -1;
+ }
+ } else {
+
+ // updates the current
+ // status accordingly
+ MessageUtils.status(false);
+
+ // the file checking failed, so
+ // the exception is displayed and
+ // the exit status is updated
+ MessageUtils.error(fileChecking.getLeft());
+ exit = -1;
+ }
+ }
+
+ // the exit status is returned,
+ // denoting whether the application
+ // was able to merge both template
+ // and data accordingly
+ return exit;
+ }
+
+ /**
+ * Ensures the data map is never pointed to a null reference.
+ */
+ private void ensureMap() {
+
+ // if the map is null, simply
+ // create a new instance
+ if (!has(map)) {
+ map = new HashMap<>();
+ }
+ }
+
+ /**
+ * Gets the file size in a human readable format.
+ *
+ * @param bytes The file size, in bytes.
+ * @return The file size in a human readable format.
+ */
+ private String getSize(long bytes) {
+ if (bytes < 1024) {
+ return bytes + " B";
+ } else {
+ int exponent = (int) (Math.log(bytes) / Math.log(1024));
+ return String.format("%.1f %cB", bytes / Math.pow(1024, exponent),
+ "KMGTPE".charAt(exponent - 1));
+ }
+ }
+
+ /**
+ * Ensures the first parameter is not null, or sets it to the second one.
+ *
+ * @param <T> The type.
+ * @param first First parameter.
+ * @param second Second parameter.
+ * @return Either the first or the second one.
+ */
+ private <T> T ensure(T first, T second) {
+ return !has(first) ? second : first;
+ }
+
+ /**
+ * Checks whether the object exists.
+ *
+ * @param object The objects.
+ * @return Boolean value indicating whether the object exists.
+ */
+ private boolean has(Object object) {
+ return object != null;
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/BooleanHandler.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/BooleanHandler.java
new file mode 100644
index 00000000000..461b9fd1705
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/BooleanHandler.java
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model.handlers;
+
+import java.util.Arrays;
+
+/**
+ * Implements a boolean handler.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class BooleanHandler implements Handler {
+
+ /**
+ * Applies the conversion to the string.
+ *
+ * @param string The string.
+ * @return A list.
+ */
+ @Override
+ public Object apply(String string) {
+ return Arrays.asList("true", "1", "yes")
+ .contains(string.toLowerCase());
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/CSVListHandler.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/CSVListHandler.java
new file mode 100644
index 00000000000..4b3d0c2e694
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/CSVListHandler.java
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model.handlers;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+/**
+ * Implements a CSV list handler.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class CSVListHandler implements Handler {
+
+ /**
+ * Applies the conversion to the string.
+ *
+ * @param string The string.
+ * @return A list.
+ */
+ @Override
+ public Object apply(String string) {
+ return Arrays.stream(string.split(",(?=(?:[^\"]*\""
+ + "[^\"]*\")*[^\"]*$)"))
+ .map(String::trim)
+ .filter(s -> !s.isEmpty())
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/Handler.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/Handler.java
new file mode 100644
index 00000000000..721224a9781
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/Handler.java
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model.handlers;
+
+/**
+ * Interface for handlers.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public interface Handler {
+
+ /**
+ * Apply the handler in the string.
+ *
+ * @param string The string.
+ * @return The resulting object.
+ */
+ Object apply(String string);
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/HandlerUtils.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/HandlerUtils.java
new file mode 100644
index 00000000000..7ab01f73281
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/HandlerUtils.java
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.islandoftex.texplate.model.handlers.BooleanHandler;
+import org.islandoftex.texplate.model.handlers.CSVListHandler;
+import org.islandoftex.texplate.model.handlers.Handler;
+
+/**
+ * Provides the map of handlers.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class HandlerUtils {
+
+ /**
+ * Gets the map of handlers.
+ *
+ * @return Map of handlers.
+ */
+ public static Map<String, Handler> getHandlers() {
+ Map<String, Handler> handlers = new HashMap<>();
+ handlers.put("to-csv-list", new CSVListHandler());
+ handlers.put("to-boolean", new BooleanHandler());
+ return handlers;
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/MergingUtils.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/MergingUtils.java
new file mode 100644
index 00000000000..d7ffbddc4da
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/MergingUtils.java
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import io.vavr.control.Try;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.exception.TemplateInitException;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.RuntimeSingleton;
+import org.apache.velocity.runtime.parser.ParseException;
+import org.islandoftex.texplate.exceptions.TemplateMergingException;
+import org.islandoftex.texplate.model.Template;
+import org.islandoftex.texplate.model.handlers.Handler;
+import org.slf4j.helpers.NOPLoggerFactory;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.Writer;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Merging utilities.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class MergingUtils {
+
+ /**
+ * Merges both template and data.
+ *
+ * @param template The template object.
+ * @param map The data map.
+ * @param output The output path.
+ * @param cmap The configuration map.
+ * @return The length of the generated output.
+ * @throws TemplateMergingException The merging failed.
+ */
+ private static long mergeTemplate(Template template,
+ Map<String, String> map, Path output,
+ Map<String, Object> cmap)
+ throws TemplateMergingException {
+
+ // create the context map
+ Map<String, Object> context = handle(template, map, cmap);
+
+ // create a file writer for
+ // the output reference
+ try (Writer writer = new FileWriter(output.toFile())) {
+
+ // the document is actually read
+ // into a string reader
+ StringReader reader = new StringReader(template.getDocument());
+
+ // load both runtime services and
+ // the template model from Velocity
+ RuntimeServices services = RuntimeSingleton.getRuntimeServices();
+ services.addProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE,
+ new NOPLoggerFactory().getLogger(""));
+ org.apache.velocity.Template reference
+ = new org.apache.velocity.Template();
+
+ // set both runtime services
+ // and document data into the
+ // template document
+ reference.setRuntimeServices(services);
+ reference.setData(services.parse(reader, reference));
+ reference.initDocument();
+
+ // create the context based on
+ // the data map previously set
+ VelocityContext entries = new VelocityContext(context);
+
+ // merge both template and data
+ // into the file writer
+ reference.merge(entries, writer);
+
+ } catch (IOException | MethodInvocationException
+ | ParseErrorException | ParseException
+ | ResourceNotFoundException
+ | TemplateInitException exception) {
+
+ // an exception has happened, so a
+ // new exception is thrown, attaching
+ // the original throwable cause
+ throw new TemplateMergingException("An error occurred while "
+ + "trying to merge the template reference with the "
+ + "provided data. Make sure the template is correct "
+ + "and try again. The raised exception might give us "
+ + "some hints on what exactly happened. Typically, "
+ + "make sure the template strictly follows the "
+ + "Velocity 2.0 language syntax.", exception);
+ }
+
+ // simply return the length of
+ // the generated output file
+ return output.toFile().length();
+ }
+
+ /**
+ * Merges template and data.
+ *
+ * @param template The template model.
+ * @param map The data map.
+ * @param output The path reference.
+ * @param cmap The configuration map.
+ * @return The length of the generated output, enclosed as a Try object.
+ */
+ public static Try<Long> merge(Template template, Map<String, String> map,
+ Path output, Map<String, Object> cmap) {
+ return Try.of(() -> mergeTemplate(template, map, output, cmap));
+ }
+
+ /**
+ * Handles the context map.
+ *
+ * @param template The template model.
+ * @param map The context map.
+ * @return The new context map.
+ */
+ private static Map<String, Object> handle(Template template,
+ Map<String, String> map,
+ Map<String, Object> cmap) {
+
+ // no handlers found
+ if (template.getHandlers() == null) {
+
+ // create a new map from the
+ // command line map and put the
+ // values from the configuration
+ // file, if absent
+ Map<String, Object> result = new HashMap<>(map);
+ cmap.forEach(result::putIfAbsent);
+ return result;
+
+ } else {
+
+ // get default handlers and
+ // set the resulting map
+ Map<String, Handler> handlers = HandlerUtils.getHandlers();
+ Map<String, Object> result = new HashMap<>();
+
+ // check each key from the map
+ map.forEach((String key, String value) -> {
+
+ // there is a handler for
+ // the current key
+ if (template.getHandlers().containsKey(key)) {
+
+ // the handler seems valid
+ if (handlers.containsKey(template.getHandlers().get(key))) {
+
+ // apply the handler and
+ // store the value in the map
+ result.put(key, handlers.get(template.
+ getHandlers().get(key)).apply(value));
+ } else {
+
+ // simply store the value
+ result.put(key, value);
+ // TODO: should we warn about an invalid handler?
+ }
+ } else {
+
+ // simply store the value
+ result.put(key, value);
+ }
+ });
+
+ // put remaining values from
+ // the configuration file, if
+ // absent
+ cmap.forEach(result::putIfAbsent);
+
+ // return the map
+ return result;
+ }
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/MessageUtils.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/MessageUtils.java
new file mode 100644
index 00000000000..7649a60e826
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/MessageUtils.java
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import org.apache.commons.text.TextStringBuilder;
+import org.apache.commons.text.WordUtils;
+
+import java.time.LocalDate;
+
+/**
+ * Message helper methods.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class MessageUtils {
+
+ // the message width
+ private static final int WIDTH = 60;
+
+ // the application version
+ private static final String VERSION = "1.0.1";
+
+ /**
+ * Prints a line in the terminal, without a line break.
+ *
+ * @param message The message to be printed.
+ */
+ public static void line(String message) {
+ System.out.print(new TextStringBuilder()
+ .appendFixedWidthPadRight(message.concat(" "), WIDTH - 9, '.')
+ .append(" ")
+ .toString()
+ );
+ }
+
+ /**
+ * Prints the status in the terminal.
+ *
+ * @param result The boolean value.
+ */
+ public static void status(boolean result) {
+ System.out.println(result ? "[ DONE ]" : "[FAILED]");
+ }
+
+ /**
+ * Prints the error in the terminal.
+ *
+ * @param throwable The throwable reference.
+ */
+ public static void error(Throwable throwable) {
+ System.out.println(
+ new TextStringBuilder("\n")
+ .appendFixedWidthPadRight("HOUSTON, WE'VE GOT"
+ + " A PROBLEM ", WIDTH, '-')
+ .append("\n")
+ .appendln(WordUtils.wrap(throwable.getMessage(), WIDTH))
+ .appendFixedWidthPadLeft("", WIDTH, '-')
+ .append("\n")
+ .toString());
+ }
+
+ /**
+ * Prints the application logo in the terminal.
+ */
+ public static void drawLogo() {
+ System.out.println(
+ " ______ __ __ ___ __ \n" +
+ "/\\__ _\\ /\\ \\ /\\ \\ /\\_ \\ /\\ \\__ \n" +
+ "\\/_/\\ \\/ __ \\ `\\`\\/'/' _____\\//\\ \\ __ \\ \\ ,_\\ __ \n" +
+ " \\ \\ \\ /'__`\\`\\/ > < /\\ '__`\\\\ \\ \\ /'__`\\ \\ \\ \\/ /'__`\\ \n" +
+ " \\ \\ \\/\\ __/ \\/'/\\`\\\\ \\ \\L\\ \\\\_\\ \\_/\\ \\L\\.\\_\\ \\ \\_/\\ __/ \n" +
+ " \\ \\_\\ \\____\\ /\\_\\\\ \\_\\ \\ ,__//\\____\\ \\__/.\\_\\\\ \\__\\ \\____\\\n" +
+ " \\/_/\\/____/ \\/_/ \\/_/\\ \\ \\/ \\/____/\\/__/\\/_/ \\/__/\\/____/\n" +
+ " \\ \\_\\ \n" +
+ " \\/_/ \n"
+ );
+ System.out.println(
+ "TeXplate " + VERSION + ", a document structure creation tool\n" +
+ "Copyright (c) " + LocalDate.now().getYear() + ", Island of TeX\n" +
+ "All rights reserved.\n"
+ );
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/PathUtils.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/PathUtils.java
new file mode 100644
index 00000000000..fa242c49801
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/PathUtils.java
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import io.vavr.control.Try;
+import org.islandoftex.texplate.Main;
+
+import java.io.FileNotFoundException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Helper methods for path handling.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class PathUtils {
+
+ // the templates folder
+ private static final String TEMPLATES_FOLDER = "templates";
+
+ // the user application folder
+ private static final String USER_APPLICATION_FOLDER = ".texplate";
+
+ /**
+ * Gets the application path.
+ *
+ * @return The application path.
+ */
+ private static Path getApplicationPath() {
+ return Try.of(() -> Paths.get(Main.class.getProtectionDomain().
+ getCodeSource().getLocation().toURI().getPath()).resolve("..").
+ normalize()).getOrElse(Paths.get("."));
+ }
+
+ /**
+ * Gets the default template path.
+ *
+ * @return The default template path.
+ */
+ private static Path getDefaultTemplatePath() {
+ return getApplicationPath().resolve(TEMPLATES_FOLDER);
+ }
+
+ /**
+ * Gets the user template path.
+ *
+ * @return The user template path.
+ */
+ private static Path getUserTemplatePath() {
+ return Try.of(() -> Paths.get(System.getProperty("user.home"),
+ USER_APPLICATION_FOLDER, TEMPLATES_FOLDER)).
+ getOrElse(Paths.get("."));
+ }
+
+ /**
+ * Searchs all paths looking for the provided template.
+ *
+ * @param name The name to be associated to a template file.
+ * @return The corresponding template file.
+ * @throws FileNotFoundException The template file could not be found.
+ */
+ private static Path searchTemplatePath(String name)
+ throws FileNotFoundException {
+ // the file has to be a TOML format,
+ // so we add the extension
+ name = name.concat(".toml");
+
+ // the first reference is based on the
+ // user template path resolved with the
+ // file name
+ Path reference = getUserTemplatePath().resolve(name);
+
+ // if the file actually exists,
+ // the search is done!
+ if (Files.exists(reference)) {
+ // return the template
+ // file reference
+ return reference;
+
+ } else {
+ // the reference was not found in the
+ // user location, so let us try the
+ // system counterpart
+ reference = getDefaultTemplatePath().resolve(name);
+
+ // if the file actually exists,
+ // the search is done!
+ if (Files.exists(reference)) {
+ // return the template
+ // file reference
+ return reference;
+
+ } else {
+ // in the system path, look for an `texplate` prefixed
+ // version as well
+ reference = getDefaultTemplatePath().resolve("texplate-" + name);
+
+ if (Files.exists(reference)) {
+ // return the template
+ // file reference
+ return reference;
+ } else {
+ // the file reference could not be
+ // found, so an exception is thrown
+ throw new FileNotFoundException("I am sorry, but the template "
+ + "file '" + name + "' could not be found in the "
+ + "default template locations (system and user). Make "
+ + "sure the reference is correct and try again. For "
+ + "reference, these are the paths I searched: '"
+ + getUserTemplatePath() + "' and '"
+ + getDefaultTemplatePath() + "' (in this order).");
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the template path based on the provided template name.
+ *
+ * @param name The template name.
+ * @return The template path, enclosed in a Try object.
+ */
+ public static Try<Path> getTemplatePath(String name) {
+ return Try.of(() -> searchTemplatePath(name));
+ }
+
+}
diff --git a/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/ValidatorUtils.java b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/ValidatorUtils.java
new file mode 100644
index 00000000000..b4007312425
--- /dev/null
+++ b/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/ValidatorUtils.java
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import io.vavr.control.Try;
+import org.islandoftex.texplate.exceptions.InvalidKeySetException;
+import org.islandoftex.texplate.model.Template;
+
+import java.util.Map;
+
+/**
+ * Helper methods for validation.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class ValidatorUtils {
+
+ /**
+ * Validates the data map based on the template requirements.
+ *
+ * @param template The template.
+ * @param map The data map.
+ * @return A boolean value indicating whether the data map is valid.
+ */
+ private static boolean validateRequirements(Template template,
+ Map<String, String> map) {
+ return template.getRequirements().isEmpty() ||
+ template.getRequirements().containsAll(map.keySet());
+ }
+
+ /**
+ * Validates the template pattern and the data map and throws an exception
+ * in case of failure.
+ *
+ * @param template The template.
+ * @param map The data map.
+ * @return The data map.
+ * @throws InvalidKeySetException There are invalid keys in the map.
+ */
+ private static Map<String, String> checkValidation(Template template,
+ Map<String, String> map)
+ throws InvalidKeySetException {
+
+ // for starters, we try to validate
+ // the template requirements
+ if (validateRequirements(template, map)) {
+
+ // everything is validated, so
+ // we simply return the map
+ return map;
+
+ } else {
+
+ // the requirements were missing,
+ // so an exception is thrown
+ throw new InvalidKeySetException("The provided map does not "
+ + "contain all the keys required by the chosen "
+ + "template. Make sure to define such keys and try "
+ + "again. Check the user manual for further details.");
+ }
+ }
+
+ /**
+ * Validates the template pattern and the data map.
+ *
+ * @param template The template.
+ * @param map The data map.
+ * @return The data map, enclosed in a Try object.
+ */
+ public static Try<Map<String, String>> validate(Template template,
+ Map<String, String> map) {
+ return Try.of(() -> checkValidation(template, map));
+ }
+
+}
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index a036967b2a5..f34ec865994 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -691,12 +691,14 @@ my @TLP_working = qw(
texdate texdef texdiff texdirflatten texdoc texdraw
texfot texilikechaps texilikecover
texliveonfly texloganalyser texlogos texmate texments
- texonly texosquery texpower texproposal texshade textualicomma texvc
+ texonly texosquery texplate texpower texproposal texshade
+ textualicomma texvc
textcase textfit textglos textgreek textmerg textopo textpath textpos
tfrupee thaienum thaispec thalie
theanodidot theanomodern theanooldstyle theatre theoremref
thesis-ekf thesis-gwu thesis-qom thesis-titlepage-fhac
- thinsp thmbox thmtools threadcol threeddice threeparttable threeparttablex
+ thinsp thmbox thmtools
+ threadcol threeddice threeparttable threeparttablex
thuaslogos thucoursework thumb thumbpdf thumbs thumby thuthesis
ticket ticollege
tikz-bayesnet tikz-cd tikz-3dplot tikz-dependency tikz-dimline
diff --git a/Master/tlpkg/libexec/ctan2tds b/Master/tlpkg/libexec/ctan2tds
index 46fc9127ff3..f64977bf7f6 100755
--- a/Master/tlpkg/libexec/ctan2tds
+++ b/Master/tlpkg/libexec/ctan2tds
@@ -1221,6 +1221,7 @@ chomp (my $ctan_root = `tlpkginfo --ctan-root`);
'thesis', "die 'skipping, contradictory licenses'", # texdev.net/2016/12/18/tex-on-windows-tex-live-versus-miktex-revisited/
'thesis-qom', "&MAKEflatten",
'thesis-titlepage-fhAC',"die 'skipping, use ...fhac'",
+ 'thorshammer', "die 'skipping, adobe required (dps)'",
'thsmc', "die 'skipping, requires nonfree font'",
'ticket', "&MAKEflatten",
'ticollege', "&MAKEflatten",
@@ -3181,6 +3182,7 @@ $standardttf = '\.ttf|\.TTC';
'texliveonfly' => '\.py$',
'texloganalyser' => 'texloganalyser',
'texosquery' => 'texosquery(|-jre[5-9])\.sh$',
+ 'texplate' => 'texplate\.sh$',
'typeoutfileinfo' => '\.sh$',
'thumbpdf' => '\.pl$',
'tlcockpit' => '\.sh$',
@@ -4010,7 +4012,8 @@ sub doscripts {
} else {
# Windows. If a shell script, usually skip, except for Java
# programs. Else copy the wrapper.
- if ($s !~ /arara|bib2gls|convertgls2bib|texosquery|tlcockpit/) {
+ if ($s !~ /arara|bib2gls|convertgls2bib
+ |texosquery|texplate|tlcockpit/x) {
next if $s =~ /\.sh$/ && $s !~ /-sys\.sh$/;
}
#
diff --git a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc
index 7f6cb8fc33d..346b0c498a2 100644
--- a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc
@@ -1,8 +1,8 @@
category Collection
shortdesc TeX auxiliary programs
-longdesc Various useful, but non-essential, support programs. Includes
+longdesc Myriad additional TeX-related support programs. Includes
longdesc programs and macros for DVI file manipulation, literate
-longdesc programming, patgen, and the TeX Works Editor.
+longdesc programming, patgen, and plenty more.
#
depend collection-basic
#
@@ -90,6 +90,7 @@ depend texfot
depend texliveonfly
depend texloganalyser
depend texosquery
+depend texplate
depend texware
depend tie
depend tlcockpit
diff --git a/Master/tlpkg/tlpsrc/texplate.tlpsrc b/Master/tlpkg/tlpsrc/texplate.tlpsrc
new file mode 100644
index 00000000000..aefd3a571c4
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/texplate.tlpsrc
@@ -0,0 +1,2 @@
+binpattern f bin/${ARCH}/${PKGNAME}
+